From 96b04da14f34e5baa9b1fb09af0cd6105dd9d665 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Mon, 5 May 2025 18:14:28 +0400 Subject: [PATCH 001/213] move action items to separate tab --- app/lib/pages/conversation_detail/page.dart | 35 ++++++++++++++++++-- app/lib/widgets/conversation_bottom_bar.dart | 13 +++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index 4167d06c7..e1d0f8137 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -49,10 +49,16 @@ class _ConversationDetailPageState extends State with Ti void initState() { super.initState(); - _controller = TabController(length: 2, vsync: this, initialIndex: 1); // Start with summary tab + _controller = TabController(length: 3, vsync: this, initialIndex: 1); // Update length to 3 for the action items tab _controller!.addListener(() { setState(() { - selectedTab = _controller!.index == 0 ? ConversationTab.transcript : ConversationTab.summary; + if (_controller!.index == 0) { + selectedTab = ConversationTab.transcript; + } else if (_controller!.index == 1) { + selectedTab = ConversationTab.summary; + } else { + selectedTab = ConversationTab.action_items; + } }); }); @@ -188,6 +194,7 @@ class _ConversationDetailPageState extends State with Ti }, ), const SummaryTab(), + const ActionItemsTab(), ], ); }), @@ -556,3 +563,27 @@ class EditSegmentWidget extends StatelessWidget { }); } } + +class ActionItemsTab extends StatelessWidget { + const ActionItemsTab({super.key}); + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: () => FocusScope.of(context).unfocus(), + child: ListView( + shrinkWrap: true, + children: [ + const SizedBox(height: 24), + Text( + 'Action Items', + style: Theme.of(context).textTheme.titleLarge!.copyWith(fontSize: 32), + ), + const SizedBox(height: 16), + const ActionItemsListWidget(), + const SizedBox(height: 150) + ], + ), + ); + } +} diff --git a/app/lib/widgets/conversation_bottom_bar.dart b/app/lib/widgets/conversation_bottom_bar.dart index d5bab17bb..51f3914fd 100644 --- a/app/lib/widgets/conversation_bottom_bar.dart +++ b/app/lib/widgets/conversation_bottom_bar.dart @@ -13,7 +13,7 @@ enum ConversationBottomBarMode { detail // For viewing completed conversations } -enum ConversationTab { transcript, summary } +enum ConversationTab { transcript, summary, action_items } class ConversationBottomBar extends StatelessWidget { final ConversationBottomBarMode mode; @@ -71,6 +71,9 @@ class ConversationBottomBar extends StatelessWidget { // Stop button or Summary tab if (mode == ConversationBottomBarMode.recording) _buildStopButton() else _buildSummaryTab(context), + + // Action Items tab (only in detail mode) + if (mode == ConversationBottomBarMode.detail) _buildActionItemsTab(), ], ), ), @@ -164,4 +167,12 @@ class ConversationBottomBar extends StatelessWidget { }, ); } + + Widget _buildActionItemsTab() { + return TabButton( + icon: Icons.check_circle_outline, + isSelected: selectedTab == ConversationTab.action_items, + onTap: () => onTabSelected(ConversationTab.action_items), + ); + } } From 373012decc9b1b64cdc9cc827d151718f4dbfa86 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Mon, 5 May 2025 18:48:35 +0400 Subject: [PATCH 002/213] cleanup logic + wider tab --- app/lib/pages/conversation_detail/page.dart | 9 ++++++++- app/lib/widgets/conversation_bottom_bar.dart | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index e1d0f8137..d762a3d83 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -217,7 +217,14 @@ class _ConversationDetailPageState extends State with Ti hasSegments: conversation.transcriptSegments.isNotEmpty || conversation.externalIntegration != null, onTabSelected: (tab) { - int index = tab == ConversationTab.transcript ? 0 : 1; + int index; + if (tab == ConversationTab.transcript) { + index = 0; + } else if (tab == ConversationTab.summary) { + index = 1; + } else { + index = 2; // action_items tab + } _controller!.animateTo(index); }, onStopPressed: () { diff --git a/app/lib/widgets/conversation_bottom_bar.dart b/app/lib/widgets/conversation_bottom_bar.dart index 51f3914fd..b8cc95eb7 100644 --- a/app/lib/widgets/conversation_bottom_bar.dart +++ b/app/lib/widgets/conversation_bottom_bar.dart @@ -49,7 +49,7 @@ class ConversationBottomBar extends StatelessWidget { borderRadius: BorderRadius.circular(28), child: Container( height: 56, - width: mode == ConversationBottomBarMode.recording ? 180 : 290, + width: mode == ConversationBottomBarMode.recording ? 180 : 360, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), decoration: BoxDecoration( color: Colors.grey.shade900, From 594922c25a28df7a05c41e64a79247b93cffbdb3 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Mon, 5 May 2025 22:49:27 +0400 Subject: [PATCH 003/213] cleanup --- app/lib/pages/conversation_detail/page.dart | 21 +++++++++++++------- app/lib/widgets/conversation_bottom_bar.dart | 2 -- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index d762a3d83..a12ff96d6 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -49,7 +49,7 @@ class _ConversationDetailPageState extends State with Ti void initState() { super.initState(); - _controller = TabController(length: 3, vsync: this, initialIndex: 1); // Update length to 3 for the action items tab + _controller = TabController(length: 3, vsync: this, initialIndex: 1); // Start with summary tab _controller!.addListener(() { setState(() { if (_controller!.index == 0) { @@ -218,12 +218,19 @@ class _ConversationDetailPageState extends State with Ti conversation.transcriptSegments.isNotEmpty || conversation.externalIntegration != null, onTabSelected: (tab) { int index; - if (tab == ConversationTab.transcript) { - index = 0; - } else if (tab == ConversationTab.summary) { - index = 1; - } else { - index = 2; // action_items tab + switch (tab) { + case ConversationTab.transcript: + index = 0; + break; + case ConversationTab.summary: + index = 1; + break; + case ConversationTab.action_items: + index = 2; + break; + default: + debugPrint('Invalid tab selected: $tab'); + index = 1; // Default to summary tab } _controller!.animateTo(index); }, diff --git a/app/lib/widgets/conversation_bottom_bar.dart b/app/lib/widgets/conversation_bottom_bar.dart index b8cc95eb7..7a3e94ffa 100644 --- a/app/lib/widgets/conversation_bottom_bar.dart +++ b/app/lib/widgets/conversation_bottom_bar.dart @@ -71,8 +71,6 @@ class ConversationBottomBar extends StatelessWidget { // Stop button or Summary tab if (mode == ConversationBottomBarMode.recording) _buildStopButton() else _buildSummaryTab(context), - - // Action Items tab (only in detail mode) if (mode == ConversationBottomBarMode.detail) _buildActionItemsTab(), ], ), From 6dc9c5fd8a07ee683328fa95331a3221c5c9d248 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Mon, 5 May 2025 22:58:53 +0400 Subject: [PATCH 004/213] change dummy if to smart switch --- app/lib/pages/conversation_detail/page.dart | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index a12ff96d6..9f8ed977c 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -52,12 +52,19 @@ class _ConversationDetailPageState extends State with Ti _controller = TabController(length: 3, vsync: this, initialIndex: 1); // Start with summary tab _controller!.addListener(() { setState(() { - if (_controller!.index == 0) { - selectedTab = ConversationTab.transcript; - } else if (_controller!.index == 1) { - selectedTab = ConversationTab.summary; - } else { - selectedTab = ConversationTab.action_items; + switch (_controller!.index) { + case 0: + selectedTab = ConversationTab.transcript; + break; + case 1: + selectedTab = ConversationTab.summary; + break; + case 2: + selectedTab = ConversationTab.action_items; + break; + default: + debugPrint('Invalid tab index: ${_controller!.index}'); + selectedTab = ConversationTab.summary; } }); }); From c2156c4eb7818f9f01f8b836236f2565adc1f172 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Mon, 5 May 2025 23:28:17 +0400 Subject: [PATCH 005/213] fix case swtich logic + remove redudant title --- app/lib/pages/conversation_detail/page.dart | 5 ----- app/lib/widgets/conversation_bottom_bar.dart | 12 +++++++++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index 9f8ed977c..bfafed2e9 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -596,11 +596,6 @@ class ActionItemsTab extends StatelessWidget { shrinkWrap: true, children: [ const SizedBox(height: 24), - Text( - 'Action Items', - style: Theme.of(context).textTheme.titleLarge!.copyWith(fontSize: 32), - ), - const SizedBox(height: 16), const ActionItemsListWidget(), const SizedBox(height: 150) ], diff --git a/app/lib/widgets/conversation_bottom_bar.dart b/app/lib/widgets/conversation_bottom_bar.dart index 7a3e94ffa..9b7ccead8 100644 --- a/app/lib/widgets/conversation_bottom_bar.dart +++ b/app/lib/widgets/conversation_bottom_bar.dart @@ -69,9 +69,15 @@ class ConversationBottomBar extends StatelessWidget { // Transcript tab _buildTranscriptTab(), - // Stop button or Summary tab - if (mode == ConversationBottomBarMode.recording) _buildStopButton() else _buildSummaryTab(context), - if (mode == ConversationBottomBarMode.detail) _buildActionItemsTab(), + // Stop button or Summary/Action Items tabs + ...switch (mode) { + ConversationBottomBarMode.recording => [_buildStopButton()], + ConversationBottomBarMode.detail => [ + _buildSummaryTab(context), + _buildActionItemsTab(), + ], + _ => [_buildSummaryTab(context)], + }, ], ), ), From ac3e2295aaf4a9acdc8b057fa34e8c4b05fe71fd Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Mon, 5 May 2025 23:53:40 +0400 Subject: [PATCH 006/213] add time info at home screen. scmall and tiny --- app/lib/backend/schema/conversation.dart | 15 +++++++++ .../pages/conversation_detail/widgets.dart | 2 +- .../widgets/conversation_list_item.dart | 33 ++++++++++++++++--- .../synced_conversation_list_item.dart | 33 ++++++++++++++++--- app/lib/utils/other/time_utils.dart | 24 ++++++++++++++ 5 files changed, 96 insertions(+), 11 deletions(-) diff --git a/app/lib/backend/schema/conversation.dart b/app/lib/backend/schema/conversation.dart index 5e3202fb9..ed9fdd575 100644 --- a/app/lib/backend/schema/conversation.dart +++ b/app/lib/backend/schema/conversation.dart @@ -220,6 +220,21 @@ class ServerConversation { return transcript; } } + + /// Calculates the conversation duration in seconds based on transcript segments + int getDurationInSeconds() { + if (transcriptSegments.isEmpty) return 0; + + // Find the last segment's end time + double lastEndTime = 0; + for (var segment in transcriptSegments) { + if (segment.end > lastEndTime) { + lastEndTime = segment.end; + } + } + + return lastEndTime.toInt(); + } } class SyncLocalFilesResponse { diff --git a/app/lib/pages/conversation_detail/widgets.dart b/app/lib/pages/conversation_detail/widgets.dart index a7df53d0e..a34df9f29 100644 --- a/app/lib/pages/conversation_detail/widgets.dart +++ b/app/lib/pages/conversation_detail/widgets.dart @@ -878,7 +878,7 @@ class _GetShareOptionsState extends State { changeLoadingShareTranscript(true); String content = ''' ${widget.conversation.structured.title} - + ${widget.conversation.getTranscript(generate: true)} ''' .replaceAll(' ', '') diff --git a/app/lib/pages/conversations/widgets/conversation_list_item.dart b/app/lib/pages/conversations/widgets/conversation_list_item.dart index 5510e6046..50cf1a2ba 100644 --- a/app/lib/pages/conversations/widgets/conversation_list_item.dart +++ b/app/lib/pages/conversations/widgets/conversation_list_item.dart @@ -10,6 +10,7 @@ import 'package:omi/providers/connectivity_provider.dart'; import 'package:omi/providers/conversation_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; +import 'package:omi/utils/other/time_utils.dart'; import 'package:omi/widgets/confirmation_dialog.dart'; import 'package:omi/widgets/dialog.dart'; import 'package:omi/widgets/extensions/string.dart'; @@ -229,17 +230,39 @@ class _ConversationListItemState extends State { alignment: Alignment.centerRight, child: ConversationNewStatusIndicator(text: "New 🚀"), ) - : Text( - dateTimeFormat('MMM d, h:mm a', widget.conversation.startedAt ?? widget.conversation.createdAt), - style: TextStyle(color: Colors.grey.shade400, fontSize: 14), - maxLines: 1, - textAlign: TextAlign.end, + : Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + dateTimeFormat('MMM d, h:mm a', widget.conversation.startedAt ?? widget.conversation.createdAt), + style: TextStyle(color: Colors.grey.shade400, fontSize: 14), + maxLines: 1, + textAlign: TextAlign.end, + ), + if (widget.conversation.transcriptSegments.isNotEmpty) + Text( + _getConversationDuration(), + style: TextStyle(color: Colors.grey.shade500, fontSize: 12), + maxLines: 1, + textAlign: TextAlign.end, + ), + ], ), ) ], ), ); } + + String _getConversationDuration() { + if (widget.conversation.transcriptSegments.isEmpty) return ''; + + // Get the total duration in seconds + int durationSeconds = widget.conversation.getDurationInSeconds(); + if (durationSeconds <= 0) return ''; + + return secondsToCompactDuration(durationSeconds); + } } class ConversationNewStatusIndicator extends StatefulWidget { diff --git a/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart b/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart index 597133da0..91f04b6bc 100644 --- a/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart +++ b/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart @@ -5,6 +5,7 @@ import 'package:omi/pages/conversation_detail/conversation_detail_provider.dart' import 'package:omi/pages/conversation_detail/page.dart'; import 'package:omi/providers/conversation_provider.dart'; import 'package:omi/utils/other/temp.dart'; +import 'package:omi/utils/other/time_utils.dart'; import 'package:omi/widgets/extensions/string.dart'; import 'package:provider/provider.dart'; @@ -174,15 +175,37 @@ class _SyncedConversationListItemState extends State width: 16, ), Expanded( - child: Text( - dateTimeFormat('MMM d, h:mm a', conversation.startedAt ?? conversation.createdAt), - style: TextStyle(color: Colors.grey.shade400, fontSize: 14), - maxLines: 1, - textAlign: TextAlign.end, + child: Column( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Text( + dateTimeFormat('MMM d, h:mm a', conversation.startedAt ?? conversation.createdAt), + style: TextStyle(color: Colors.grey.shade400, fontSize: 14), + maxLines: 1, + textAlign: TextAlign.end, + ), + if (conversation.transcriptSegments.isNotEmpty) + Text( + _getConversationDuration(), + style: TextStyle(color: Colors.grey.shade500, fontSize: 12), + maxLines: 1, + textAlign: TextAlign.end, + ), + ], ), ) ], ), ); } + + String _getConversationDuration() { + if (conversation.transcriptSegments.isEmpty) return ''; + + // Get the total duration in seconds + int durationSeconds = conversation.getDurationInSeconds(); + if (durationSeconds <= 0) return ''; + + return secondsToCompactDuration(durationSeconds); + } } diff --git a/app/lib/utils/other/time_utils.dart b/app/lib/utils/other/time_utils.dart index f933ee54c..89808d345 100644 --- a/app/lib/utils/other/time_utils.dart +++ b/app/lib/utils/other/time_utils.dart @@ -37,6 +37,30 @@ String secondsToHumanReadable(int seconds) { } } +/// Returns a compact representation of seconds (e.g., "10s", "5m", "2h 15m") +/// Designed for use in small UI elements like list items +String secondsToCompactDuration(int seconds) { + if (seconds < 60) { + return '${seconds}s'; + } else if (seconds < 3600) { + var minutes = (seconds / 60).floor(); + var remainingSeconds = seconds % 60; + if (remainingSeconds == 0) { + return '${minutes}m'; + } else { + return '${minutes}m ${remainingSeconds}s'; + } + } else { + var hours = (seconds / 3600).floor(); + var remainingMinutes = (seconds % 3600 / 60).floor(); + if (remainingMinutes == 0) { + return '${hours}h'; + } else { + return '${hours}h ${remainingMinutes}m'; + } + } +} + // convert seconds to hh:mm:ss format String secondsToHMS(int seconds) { var hours = (seconds / 3600).floor(); From fd6bbd59560eaa2aef2dec0195980eedd4752d8f Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Tue, 6 May 2025 00:11:35 +0400 Subject: [PATCH 007/213] make it pretty look and in details page - extra line --- .../pages/conversation_detail/widgets.dart | 24 +++++++++++++++++++ .../widgets/conversation_list_item.dart | 20 ++++++++++++---- .../synced_conversation_list_item.dart | 20 ++++++++++++---- app/lib/utils/other/time_utils.dart | 5 ++-- 4 files changed, 57 insertions(+), 12 deletions(-) diff --git a/app/lib/pages/conversation_detail/widgets.dart b/app/lib/pages/conversation_detail/widgets.dart index a34df9f29..9799d584c 100644 --- a/app/lib/pages/conversation_detail/widgets.dart +++ b/app/lib/pages/conversation_detail/widgets.dart @@ -21,6 +21,7 @@ import 'package:omi/providers/connectivity_provider.dart'; import 'package:omi/providers/conversation_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; +import 'package:omi/utils/other/time_utils.dart'; import 'package:omi/widgets/dialog.dart'; import 'package:omi/widgets/extensions/string.dart'; import 'package:provider/provider.dart'; @@ -42,6 +43,15 @@ class GetSummaryWidgets extends StatelessWidget { return startedAt == null ? dateTimeFormat('h:mm a', createdAt) : dateTimeFormat('h:mm a', startedAt); } + String _getDuration(ServerConversation conversation) { + if (conversation.transcriptSegments.isEmpty) return ''; + + int durationSeconds = conversation.getDurationInSeconds(); + if (durationSeconds <= 0) return ''; + + return secondsToHumanReadable(durationSeconds); + } + @override Widget build(BuildContext context) { return Selector>( @@ -72,6 +82,20 @@ class GetSummaryWidgets extends StatelessWidget { : '${dateTimeFormat('MMM d, yyyy', conversation.createdAt)} ${conversation.startedAt == null ? 'at' : 'from'} ${setTime(conversation.startedAt, conversation.createdAt, conversation.finishedAt)}', style: const TextStyle(color: Colors.grey, fontSize: 16), ), + if (conversation.transcriptSegments.isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 4.0), + child: Row( + children: [ + const Icon(Icons.access_time, color: Colors.grey, size: 14), + const SizedBox(width: 4), + Text( + 'Duration: ${_getDuration(conversation)}', + style: const TextStyle(color: Colors.grey, fontSize: 14), + ), + ], + ), + ), const SizedBox(height: 16), conversation.discarded ? const SizedBox.shrink() : const SizedBox(height: 8), ], diff --git a/app/lib/pages/conversations/widgets/conversation_list_item.dart b/app/lib/pages/conversations/widgets/conversation_list_item.dart index 50cf1a2ba..44e82f0b9 100644 --- a/app/lib/pages/conversations/widgets/conversation_list_item.dart +++ b/app/lib/pages/conversations/widgets/conversation_list_item.dart @@ -240,11 +240,21 @@ class _ConversationListItemState extends State { textAlign: TextAlign.end, ), if (widget.conversation.transcriptSegments.isNotEmpty) - Text( - _getConversationDuration(), - style: TextStyle(color: Colors.grey.shade500, fontSize: 12), - maxLines: 1, - textAlign: TextAlign.end, + Padding( + padding: const EdgeInsets.only(top: 2.0), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: Colors.grey.shade800, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + _getConversationDuration(), + style: TextStyle(color: Colors.grey.shade300, fontSize: 11), + maxLines: 1, + textAlign: TextAlign.end, + ), + ), ), ], ), diff --git a/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart b/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart index 91f04b6bc..a5419c7a0 100644 --- a/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart +++ b/app/lib/pages/conversations/widgets/synced_conversation_list_item.dart @@ -185,11 +185,21 @@ class _SyncedConversationListItemState extends State textAlign: TextAlign.end, ), if (conversation.transcriptSegments.isNotEmpty) - Text( - _getConversationDuration(), - style: TextStyle(color: Colors.grey.shade500, fontSize: 12), - maxLines: 1, - textAlign: TextAlign.end, + Padding( + padding: const EdgeInsets.only(top: 2.0), + child: Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), + decoration: BoxDecoration( + color: Colors.grey.shade800, + borderRadius: BorderRadius.circular(4), + ), + child: Text( + _getConversationDuration(), + style: TextStyle(color: Colors.grey.shade300, fontSize: 11), + maxLines: 1, + textAlign: TextAlign.end, + ), + ), ), ], ), diff --git a/app/lib/utils/other/time_utils.dart b/app/lib/utils/other/time_utils.dart index 89808d345..9b0eca41c 100644 --- a/app/lib/utils/other/time_utils.dart +++ b/app/lib/utils/other/time_utils.dart @@ -45,15 +45,16 @@ String secondsToCompactDuration(int seconds) { } else if (seconds < 3600) { var minutes = (seconds / 60).floor(); var remainingSeconds = seconds % 60; - if (remainingSeconds == 0) { + if (remainingSeconds == 0 || minutes >= 10) { return '${minutes}m'; } else { + // Only show seconds for durations less than 10 minutes return '${minutes}m ${remainingSeconds}s'; } } else { var hours = (seconds / 3600).floor(); var remainingMinutes = (seconds % 3600 / 60).floor(); - if (remainingMinutes == 0) { + if (remainingMinutes == 0 || hours >= 10) { return '${hours}h'; } else { return '${hours}h ${remainingMinutes}m'; From 5b84385754a8d1ed9b9c4fb17bf3dd309926ec23 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Sun, 11 May 2025 07:49:48 +0400 Subject: [PATCH 008/213] add empty screen notice --- app/lib/pages/conversation_detail/page.dart | 59 ++++++++++++++++++--- 1 file changed, 52 insertions(+), 7 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index bfafed2e9..16936f2b2 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -592,13 +592,58 @@ class ActionItemsTab extends StatelessWidget { Widget build(BuildContext context) { return GestureDetector( onTap: () => FocusScope.of(context).unfocus(), - child: ListView( - shrinkWrap: true, - children: [ - const SizedBox(height: 24), - const ActionItemsListWidget(), - const SizedBox(height: 150) - ], + child: Consumer( + builder: (context, provider, child) { + final hasActionItems = provider.conversation.structured.actionItems + .where((item) => !item.deleted) + .isNotEmpty; + + return ListView( + shrinkWrap: true, + children: [ + const SizedBox(height: 24), + if (hasActionItems) + const ActionItemsListWidget() + else + _buildEmptyState(context), + const SizedBox(height: 150) + ], + ); + }, + ), + ); + } + + Widget _buildEmptyState(BuildContext context) { + return Center( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 24.0, vertical: 40.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Icon( + Icons.check_circle_outline, + size: 72, + color: Colors.grey, + ), + const SizedBox(height: 24), + Text( + 'No Action Items', + style: Theme.of(context).textTheme.headlineSmall?.copyWith( + color: Colors.white, + ), + ), + const SizedBox(height: 12), + Text( + 'This memory doesn\'t have any action items yet. They\'ll appear here when your conversations include tasks or to-dos.', + textAlign: TextAlign.center, + style: TextStyle( + color: Colors.grey.shade400, + fontSize: 16, + ), + ), + ], + ), ), ); } From ac7fcc005ddcc8f5e498429a5c958e51a5edcf89 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Sun, 11 May 2025 17:28:18 +0400 Subject: [PATCH 009/213] Enhance Memories Review and Management UI - Implemented a new memory processing function to handle individual memory approvals and rejections, providing user feedback via SnackBars. - Improved the layout and styling of the memories review page, including adjustments to padding, font sizes, and margins for better visual consistency. - Added a memory management sheet for bulk actions, allowing users to make all memories private or public and delete all memories with confirmation. - Introduced a category filter with concise display names for better usability. - Refactored the MemoriesProvider to manage memory visibility and filtering more efficiently, ensuring a smoother user experience. --- .../pages/memories/memories_review_page.dart | 305 ++++++++------ app/lib/pages/memories/page.dart | 395 +++++++++++++----- .../pages/memories/widgets/category_chip.dart | 119 +++++- .../pages/memories/widgets/memory_item.dart | 58 ++- .../widgets/memory_management_sheet.dart | 280 +++++++++++++ .../memories/widgets/memory_review_sheet.dart | 26 +- app/lib/providers/memories_provider.dart | 173 +++++--- app/lib/utils/ui_guidelines.dart | 164 ++++++++ 8 files changed, 1186 insertions(+), 334 deletions(-) create mode 100644 app/lib/pages/memories/widgets/memory_management_sheet.dart create mode 100644 app/lib/utils/ui_guidelines.dart diff --git a/app/lib/pages/memories/memories_review_page.dart b/app/lib/pages/memories/memories_review_page.dart index 5c1528b52..5417c64a0 100644 --- a/app/lib/pages/memories/memories_review_page.dart +++ b/app/lib/pages/memories/memories_review_page.dart @@ -98,6 +98,46 @@ class _MemoriesReviewPageState extends State { } } + void _processSingleMemory(Memory memory, bool approve) async { + if (_isProcessing) return; + + setState(() => _isProcessing = true); + + // Process the single memory + context.read().reviewMemory(memory, approve); + + setState(() { + remainingMemories.remove(memory); + displayedMemories = selectedCategory == null + ? List.from(remainingMemories) + : remainingMemories.where((f) => f.category == selectedCategory).toList(); + _isProcessing = false; + }); + + // Show feedback + if (!mounted) return; + + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text( + approve ? 'Memory saved' : 'Memory discarded', + style: const TextStyle(color: Colors.white), + ), + backgroundColor: Colors.grey.shade800, + duration: const Duration(seconds: 2), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + margin: const EdgeInsets.fromLTRB(16, 0, 16, 16), + ), + ); + + if (remainingMemories.isEmpty) { + Navigator.pop(context); + } + } + @override Widget build(BuildContext context) { return Consumer(builder: (context, provider, child) { @@ -110,9 +150,9 @@ class _MemoriesReviewPageState extends State { children: [ const Text('Review Memories'), Text( - '${displayedMemories.length} ${selectedCategory != null ? "in ${selectedCategory.toString().split('.').last}" : "total"}', + _getFilterSubtitle(), style: TextStyle( - fontSize: 14, + fontSize: 13, color: Colors.grey.shade400, fontWeight: FontWeight.normal, ), @@ -123,8 +163,8 @@ class _MemoriesReviewPageState extends State { body: Column( children: [ Container( - height: 50, - margin: const EdgeInsets.symmetric(vertical: 8), + height: 46, + margin: const EdgeInsets.only(top: 4, bottom: 8), child: ListView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(horizontal: 16), @@ -137,6 +177,7 @@ class _MemoriesReviewPageState extends State { style: TextStyle( color: selectedCategory == null ? Colors.black : Colors.white70, fontWeight: selectedCategory == null ? FontWeight.w600 : FontWeight.normal, + fontSize: 13, ), ), selected: selectedCategory == null, @@ -145,20 +186,27 @@ class _MemoriesReviewPageState extends State { selectedColor: Colors.white, checkmarkColor: Colors.black, showCheckmark: false, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), ), ), ...categoryCounts.entries.map((entry) { final category = entry.key; final count = entry.value; + + // Format category name to be more concise + String categoryName = category.toString().split('.').last; + // Capitalize first letter only + categoryName = categoryName[0].toUpperCase() + categoryName.substring(1); + return Padding( padding: const EdgeInsets.only(right: 8), child: FilterChip( label: Text( - '${category.toString().split('.').last} ($count)', + '$categoryName ($count)', style: TextStyle( color: selectedCategory == category ? Colors.black : Colors.white70, fontWeight: selectedCategory == category ? FontWeight.w600 : FontWeight.normal, + fontSize: 13, ), ), selected: selectedCategory == category, @@ -167,7 +215,7 @@ class _MemoriesReviewPageState extends State { selectedColor: Colors.white, checkmarkColor: Colors.black, showCheckmark: false, - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), ), ); }), @@ -185,10 +233,10 @@ class _MemoriesReviewPageState extends State { Text( selectedCategory == null ? 'All memories have been reviewed' - : 'No memories to review in this category', + : 'No memories in this category', style: TextStyle( color: Colors.grey.shade400, - fontSize: 18, + fontSize: 16, ), ), ], @@ -200,16 +248,16 @@ class _MemoriesReviewPageState extends State { itemBuilder: (context, index) { final memory = displayedMemories[index]; return Container( - margin: const EdgeInsets.only(bottom: 12), + margin: const EdgeInsets.only(bottom: 10), decoration: BoxDecoration( color: Colors.grey.shade900, - borderRadius: BorderRadius.circular(16), + borderRadius: BorderRadius.circular(12), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.all(14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -217,108 +265,85 @@ class _MemoriesReviewPageState extends State { category: memory.category, showIcon: true, ), - const SizedBox(height: 12), + const SizedBox(height: 10), Text( memory.content.decodeString, style: const TextStyle( color: Colors.white, - fontSize: 16, + fontSize: 15, height: 1.4, ), ), ], ), ), - Row( - children: [ - Expanded( - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: Colors.transparent, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(16), + Container( + decoration: BoxDecoration( + color: Colors.grey.shade800, + borderRadius: const BorderRadius.vertical( + bottom: Radius.circular(12), + ), + ), + padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10), + child: Row( + children: [ + Expanded( + child: GestureDetector( + onTap: () => _processSingleMemory(memory, false), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(8), ), - ), - ), - onPressed: _isProcessing - ? null - : () { - provider.reviewMemory(memory, false); - setState(() { - remainingMemories.remove(memory); - displayedMemories.remove(memory); - }); - if (remainingMemories.isEmpty) { - Navigator.pop(context); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.delete_outline, size: 18, color: Colors.red.shade400), - const SizedBox(width: 8), - Text( - 'Discard', - style: TextStyle( - color: Colors.red.shade400, - fontSize: 15, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.delete_outline, size: 16, color: Colors.white70), + SizedBox(width: 6), + Text( + 'Discard', + style: TextStyle( + color: Colors.white70, + fontSize: 13, + fontWeight: FontWeight.w500, + ), ), - ), - ], + ], + ), ), ), ), - ), - Container( - width: 1, - height: 45, - color: Colors.white.withOpacity(0.1), - ), - Expanded( - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: Colors.transparent, - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - bottomRight: Radius.circular(16), + const SizedBox(width: 10), + Expanded( + child: GestureDetector( + onTap: () => _processSingleMemory(memory, true), + child: Container( + padding: const EdgeInsets.symmetric(vertical: 8), + decoration: BoxDecoration( + color: Colors.blue.shade700, + borderRadius: BorderRadius.circular(8), ), - ), - ), - onPressed: _isProcessing - ? null - : () { - provider.reviewMemory(memory, true); - setState(() { - remainingMemories.remove(memory); - displayedMemories.remove(memory); - }); - if (remainingMemories.isEmpty) { - Navigator.pop(context); - } - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 12), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Icon(Icons.check, size: 18, color: Colors.white), - const SizedBox(width: 8), - Text( - 'Save', - style: TextStyle( - color: Colors.grey.shade100, - fontSize: 15, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.check, size: 16, color: Colors.white), + SizedBox(width: 6), + Text( + 'Save', + style: TextStyle( + color: Colors.white, + fontSize: 13, + fontWeight: FontWeight.w500, + ), ), - ), - ], + ], + ), ), ), ), - ), - ], + ], + ), ), ], ), @@ -351,56 +376,59 @@ class _MemoriesReviewPageState extends State { : Row( children: [ Expanded( - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: Colors.red.shade900.withOpacity(0.3), + child: GestureDetector( + onTap: () => _processBatchAction(false), + child: Container( padding: const EdgeInsets.symmetric(vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + decoration: BoxDecoration( + color: Colors.white.withOpacity(0.1), + borderRadius: BorderRadius.circular(10), ), - ), - onPressed: () => _processBatchAction(false), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.delete_outline, size: 18, color: Colors.red.shade400), - const SizedBox(width: 8), - Text( - 'Discard all', - style: TextStyle( - color: Colors.red.shade400, - fontSize: 15, + alignment: Alignment.center, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.delete_outline, size: 18, color: Colors.white70), + SizedBox(width: 8), + Text( + 'Discard All', + style: TextStyle( + color: Colors.white70, + fontSize: 14, + fontWeight: FontWeight.w500, + ), ), - ), - ], + ], + ), ), ), ), const SizedBox(width: 12), Expanded( - child: TextButton( - style: TextButton.styleFrom( - backgroundColor: Colors.white, + child: GestureDetector( + onTap: () => _processBatchAction(true), + child: Container( padding: const EdgeInsets.symmetric(vertical: 12), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + decoration: BoxDecoration( + color: Colors.blue.shade700, + borderRadius: BorderRadius.circular(10), ), - ), - onPressed: () => _processBatchAction(true), - child: const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.check, size: 18, color: Colors.black), - SizedBox(width: 8), - Text( - 'Save all', - style: TextStyle( - color: Colors.black, - fontSize: 15, - fontWeight: FontWeight.w600, + alignment: Alignment.center, + child: const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.check, size: 18, color: Colors.white), + SizedBox(width: 8), + Text( + 'Save All', + style: TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.w500, + ), ), - ), - ], + ], + ), ), ), ), @@ -412,4 +440,15 @@ class _MemoriesReviewPageState extends State { ); }); } + + String _getFilterSubtitle() { + if (selectedCategory == null) { + return '${displayedMemories.length} memories to review'; + } + + String categoryName = selectedCategory.toString().split('.').last; + categoryName = categoryName[0].toUpperCase() + categoryName.substring(1); + + return '${displayedMemories.length} ${categoryName} memories'; + } } diff --git a/app/lib/pages/memories/page.dart b/app/lib/pages/memories/page.dart index 6fc0c207b..e2fbf6e4c 100644 --- a/app/lib/pages/memories/page.dart +++ b/app/lib/pages/memories/page.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:omi/backend/schema/memory.dart'; import 'package:omi/providers/memories_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; +import 'package:omi/utils/ui_guidelines.dart'; import 'package:omi/widgets/extensions/functions.dart'; import 'package:provider/provider.dart'; @@ -9,6 +10,8 @@ import 'widgets/memory_edit_sheet.dart'; import 'widgets/memory_item.dart'; import 'widgets/memory_dialog.dart'; import 'widgets/memory_review_sheet.dart'; +import 'widgets/memory_management_sheet.dart'; +import 'widgets/category_chip.dart'; class MemoriesPage extends StatefulWidget { const MemoriesPage({super.key}); @@ -19,10 +22,13 @@ class MemoriesPage extends StatefulWidget { class MemoriesPageState extends State { final TextEditingController _searchController = TextEditingController(); + MemoryCategory? _selectedCategory; + final ScrollController _scrollController = ScrollController(); @override void dispose() { _searchController.dispose(); + _scrollController.dispose(); super.dispose(); } @@ -39,10 +45,79 @@ class MemoriesPageState extends State { super.initState(); } + void _filterByCategory(MemoryCategory? category) { + setState(() { + _selectedCategory = category; + }); + + // Apply category filter to provider + context.read().setCategoryFilter(category); + } + + Map _getCategoryCounts(List memories) { + var counts = {}; + for (var memory in memories) { + counts[memory.category] = (counts[memory.category] ?? 0) + 1; + } + return counts; + } + + Widget _buildSearchBar() { + return Consumer( + builder: (context, provider, _) { + return Padding( + padding: const EdgeInsets.fromLTRB(16, 4, 16, 4), + child: SearchBar( + hintText: 'Search memories', + leading: const Icon(Icons.search, color: Colors.white70, size: 18), + backgroundColor: WidgetStateProperty.all(AppStyles.backgroundSecondary), + elevation: WidgetStateProperty.all(0), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + ), + controller: _searchController, + trailing: provider.searchQuery.isNotEmpty + ? [ + IconButton( + icon: const Icon(Icons.close, color: Colors.white70, size: 16), + padding: EdgeInsets.zero, + constraints: const BoxConstraints( + minHeight: 36, + minWidth: 36, + ), + onPressed: () { + _searchController.clear(); + setState(() {}); + provider.setSearchQuery(''); + }, + ) + ] + : null, + hintStyle: WidgetStateProperty.all( + TextStyle(color: AppStyles.textTertiary, fontSize: 14), + ), + textStyle: WidgetStateProperty.all( + TextStyle(color: AppStyles.textPrimary, fontSize: 14), + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppStyles.radiusMedium), + ), + ), + onChanged: (value) => provider.setSearchQuery(value), + ), + ); + } + ); + } + @override Widget build(BuildContext context) { return Consumer( builder: (context, provider, _) { + final unreviewedCount = provider.unreviewed.length; + final categoryCounts = _getCategoryCounts(provider.memories); + return PopScope( canPop: true, child: Scaffold( @@ -52,110 +127,201 @@ class MemoriesPageState extends State { child: CircularProgressIndicator( valueColor: AlwaysStoppedAnimation(Colors.white), )) - : CustomScrollView( - slivers: [ - SliverAppBar( - backgroundColor: Theme.of(context).colorScheme.primary, - pinned: true, - snap: true, - floating: true, - title: const Text('My Memory'), - actions: [ - IconButton( - icon: const Icon(Icons.delete_sweep_outlined), - onPressed: () { - _showDeleteAllConfirmation(context, provider); - }, - ), - IconButton( - icon: const Icon(Icons.add), - onPressed: () { - showMemoryDialog(context, provider); - MixpanelManager().memoriesPageCreateMemoryBtn(); - }, - ), - ], - bottom: PreferredSize( - preferredSize: const Size.fromHeight(68), - child: Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 16, 10), - child: SearchBar( - hintText: 'Search Omi\'s memory about you', - leading: const Icon(Icons.search, color: Colors.white70), - backgroundColor: WidgetStateProperty.all(Colors.grey.shade900), - elevation: WidgetStateProperty.all(0), - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric(horizontal: 10, vertical: 6), - ), - controller: _searchController, - trailing: provider.searchQuery.isNotEmpty - ? [ - IconButton( - icon: const Icon(Icons.close, color: Colors.white70), - onPressed: () { - _searchController.clear(); - setState(() {}); - provider.setSearchQuery(''); - }, - ) - ] - : null, - hintStyle: WidgetStateProperty.all( - TextStyle(color: Colors.grey.shade400, fontSize: 14), - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), + : NestedScrollView( + controller: _scrollController, + headerSliverBuilder: (context, innerBoxIsScrolled) { + return [ + // AppBar with the title and action buttons + SliverAppBar( + backgroundColor: Theme.of(context).colorScheme.primary, + pinned: true, + centerTitle: true, + title: const Text('Memories', style: AppStyles.title), + leading: null, + automaticallyImplyLeading: true, + titleSpacing: 0, + actions: [ + IconButton( + icon: Stack( + alignment: Alignment.center, + children: [ + Icon( + Icons.reviews_outlined, + color: unreviewedCount > 0 ? Colors.white : Colors.grey.shade600, + size: 22, + ), + if (unreviewedCount > 0) + Positioned( + top: 0, + right: 0, + child: Container( + padding: const EdgeInsets.all(2), + decoration: BoxDecoration( + color: Colors.red, + borderRadius: BorderRadius.circular(8), + ), + constraints: const BoxConstraints( + minWidth: 16, + minHeight: 16, + ), + child: Text( + '$unreviewedCount', + style: const TextStyle( + color: Colors.white, + fontSize: 10, + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, + ), + ), + ), + ], ), - onChanged: (value) => provider.setSearchQuery(value), + onPressed: unreviewedCount > 0 + ? () { + _showReviewSheet(provider.unreviewed); + MixpanelManager().memoriesPageReviewBtn(); + } + : null, + tooltip: unreviewedCount > 0 ? 'Review memories' : 'No memories to review', ), - ), + IconButton( + icon: const Icon(Icons.settings), + onPressed: () { + _showMemoryManagementSheet(context, provider); + }, + tooltip: 'Manage memories', + ), + IconButton( + icon: const Icon(Icons.add), + onPressed: () { + showMemoryDialog(context, provider); + MixpanelManager().memoriesPageCreateMemoryBtn(); + }, + ), + ], ), - ), - SliverPadding( - padding: const EdgeInsets.all(16), - sliver: provider.filteredMemories.isEmpty - ? SliverFillRemaining( - child: Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Icon(Icons.note_add, size: 48, color: Colors.grey.shade600), - const SizedBox(height: 16), - Text( - provider.searchQuery.isEmpty ? 'No memories yet' : 'No memories found', + + // Category filter + if (categoryCounts.isNotEmpty) + SliverToBoxAdapter( + child: Container( + height: 50, + margin: const EdgeInsets.fromLTRB(0, 0, 0, 8), + child: ListView( + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(horizontal: 16), + children: [ + Padding( + padding: const EdgeInsets.only(right: 8), + child: FilterChip( + label: Text( + 'All (${provider.memories.length})', style: TextStyle( - color: Colors.grey.shade400, - fontSize: 18, + color: _selectedCategory == null ? Colors.black : Colors.white70, + fontWeight: _selectedCategory == null ? FontWeight.w600 : FontWeight.normal, + fontSize: 13, ), ), - if (provider.searchQuery.isEmpty) ...[ - const SizedBox(height: 8), - TextButton( - onPressed: () => showMemoryDialog(context, provider), - child: const Text('Add your first memory'), - ), - ], - ], + selected: _selectedCategory == null, + onSelected: (_) => _filterByCategory(null), + backgroundColor: AppStyles.backgroundTertiary, + selectedColor: Colors.white, + checkmarkColor: Colors.black, + showCheckmark: false, + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + ), ), - ), - ) - : SliverList( - delegate: SliverChildBuilderDelegate( - (context, index) { - final memory = provider.filteredMemories[index]; - return MemoryItem( - memory: memory, - provider: provider, - onTap: _showQuickEditSheet, + ...categoryCounts.entries.map((entry) { + final category = entry.key; + final count = entry.value; + + // Format category name to be more concise + String categoryName = category.toString().split('.').last; + // Capitalize first letter only + categoryName = categoryName[0].toUpperCase() + categoryName.substring(1); + + return Padding( + padding: const EdgeInsets.only(right: 8), + child: FilterChip( + label: Text( + '$categoryName ($count)', + style: TextStyle( + color: _selectedCategory == category ? Colors.black : Colors.white70, + fontWeight: _selectedCategory == category ? FontWeight.w600 : FontWeight.normal, + fontSize: 13, + ), + ), + selected: _selectedCategory == category, + onSelected: (_) => _filterByCategory(category), + backgroundColor: AppStyles.backgroundTertiary, + selectedColor: Colors.white, + checkmarkColor: Colors.black, + showCheckmark: false, + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + ), ); - }, - childCount: provider.filteredMemories.length, - ), + }), + ], ), - ), - ], + ), + ), + + // Search bar that appears when scrolling + SliverPersistentHeader( + pinned: true, + floating: true, + delegate: _SliverSearchBarDelegate( + minHeight: 0, + maxHeight: 60, + child: Container( + color: Theme.of(context).colorScheme.primary, + child: _buildSearchBar(), + ), + ), + ), + ]; + }, + body: provider.filteredMemories.isEmpty + ? Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(Icons.note_add, size: 48, color: Colors.grey.shade600), + const SizedBox(height: 16), + Text( + provider.searchQuery.isEmpty && _selectedCategory == null + ? 'No memories yet' + : _selectedCategory != null + ? 'No memories in this category' + : 'No memories found', + style: TextStyle( + color: Colors.grey.shade400, + fontSize: 18, + ), + ), + if (provider.searchQuery.isEmpty && _selectedCategory == null) ...[ + const SizedBox(height: 8), + TextButton( + onPressed: () => showMemoryDialog(context, provider), + child: const Text('Add your first memory'), + ), + ], + ], + ), + ) + : ListView.builder( + padding: const EdgeInsets.all(16), + itemCount: provider.filteredMemories.length, + itemBuilder: (context, index) { + final memory = provider.filteredMemories[index]; + return MemoryItem( + memory: memory, + provider: provider, + onTap: _showQuickEditSheet, + ); + }, + ), ), ), ); @@ -245,4 +411,43 @@ class MemoriesPageState extends State { ), ); } + + void _showMemoryManagementSheet(BuildContext context, MemoriesProvider provider) { + showModalBottomSheet( + context: context, + backgroundColor: Colors.transparent, + isScrollControlled: true, + builder: (context) => MemoryManagementSheet(provider: provider), + ); + } +} + +class _SliverSearchBarDelegate extends SliverPersistentHeaderDelegate { + final double minHeight; + final double maxHeight; + final Widget child; + + _SliverSearchBarDelegate({ + required this.minHeight, + required this.maxHeight, + required this.child, + }); + + @override + double get minExtent => minHeight; + + @override + double get maxExtent => maxHeight; + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + return SizedBox.expand(child: child); + } + + @override + bool shouldRebuild(_SliverSearchBarDelegate oldDelegate) { + return maxHeight != oldDelegate.maxHeight || + minHeight != oldDelegate.minHeight || + child != oldDelegate.child; + } } diff --git a/app/lib/pages/memories/widgets/category_chip.dart b/app/lib/pages/memories/widgets/category_chip.dart index fff4bc54f..409db1fd9 100644 --- a/app/lib/pages/memories/widgets/category_chip.dart +++ b/app/lib/pages/memories/widgets/category_chip.dart @@ -19,34 +19,126 @@ class CategoryChip extends StatelessWidget { this.showCheckmark = false, }); + Color _getCategoryColor() { + switch (category) { + case MemoryCategory.core: + return Colors.blue; + case MemoryCategory.lifestyle: + return Colors.purple; + case MemoryCategory.interests: + return Colors.green; + case MemoryCategory.work: + return Colors.orange; + case MemoryCategory.skills: + return Colors.red; + case MemoryCategory.hobbies: + return Colors.amber; + case MemoryCategory.habits: + return Colors.teal; + case MemoryCategory.learnings: + return Colors.indigo; + case MemoryCategory.other: + return Colors.grey; + } + } + + IconData _getCategoryIcon() { + switch (category) { + case MemoryCategory.core: + return Icons.info_outline; + case MemoryCategory.lifestyle: + return Icons.home_outlined; + case MemoryCategory.interests: + return Icons.star_outline; + case MemoryCategory.work: + return Icons.work_outline; + case MemoryCategory.skills: + return Icons.psychology_outlined; + case MemoryCategory.hobbies: + return Icons.sports_esports_outlined; + case MemoryCategory.habits: + return Icons.repeat_outlined; + case MemoryCategory.learnings: + return Icons.school_outlined; + case MemoryCategory.other: + return Icons.label_outline; + } + } + @override Widget build(BuildContext context) { final categoryName = category.toString().split('.').last; - final displayName = count != null ? '$categoryName ($count)' : categoryName; + // Use shorter display names for categories + String displayName; + switch (category) { + case MemoryCategory.core: + displayName = "Core"; + break; + case MemoryCategory.lifestyle: + displayName = "Life"; + break; + case MemoryCategory.interests: + displayName = "Int"; + break; + case MemoryCategory.work: + displayName = "Work"; + break; + case MemoryCategory.skills: + displayName = "Skills"; + break; + case MemoryCategory.hobbies: + displayName = "Hobby"; + break; + case MemoryCategory.habits: + displayName = "Habit"; + break; + case MemoryCategory.learnings: + displayName = "Learn"; + break; + case MemoryCategory.other: + displayName = "Other"; + break; + } + + final countText = count != null ? ' ($count)' : ''; + + final categoryColor = _getCategoryColor(); + final categoryIcon = _getCategoryIcon(); Widget chip = Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + height: 26, + padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 0), decoration: BoxDecoration( - color: isSelected ? (onTap != null ? Colors.white : Colors.white.withOpacity(0.1)) : Colors.grey.shade800, - borderRadius: BorderRadius.circular(16), - border: isSelected && onTap == null ? Border.all(color: Colors.white, width: 1) : null, + color: isSelected + ? (onTap != null ? categoryColor : categoryColor.withOpacity(0.15)) + : Colors.grey.shade800.withOpacity(0.6), + borderRadius: BorderRadius.circular(13), + border: isSelected && onTap == null + ? Border.all(color: categoryColor, width: 1) + : null, ), child: Row( mainAxisSize: MainAxisSize.min, children: [ if (showIcon) ...[ - const Icon(Icons.label_outline, size: 14, color: Colors.white), + Icon( + categoryIcon, + size: 14, + color: isSelected && onTap != null ? Colors.white : categoryColor, + ), const SizedBox(width: 4), ], if (showCheckmark && isSelected) ...[ - const Icon(Icons.check, size: 14, color: Colors.white), - const SizedBox(width: 4), + const Icon(Icons.check, size: 12, color: Colors.white), + const SizedBox(width: 2), ], Text( - displayName, + displayName + countText, style: TextStyle( - color: isSelected ? (onTap != null ? Colors.black : Colors.white) : Colors.white70, - fontSize: 13, + color: isSelected + ? (onTap != null ? Colors.white : categoryColor) + : Colors.white70, + fontSize: 12, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), @@ -61,6 +153,9 @@ class CategoryChip extends StatelessWidget { ); } - return chip; + return Align( + alignment: Alignment.centerLeft, + child: chip, + ); } } diff --git a/app/lib/pages/memories/widgets/memory_item.dart b/app/lib/pages/memories/widgets/memory_item.dart index f5f19d61e..76fb371d4 100644 --- a/app/lib/pages/memories/widgets/memory_item.dart +++ b/app/lib/pages/memories/widgets/memory_item.dart @@ -2,9 +2,11 @@ import 'package:flutter/material.dart'; import 'package:omi/backend/schema/memory.dart'; import 'package:omi/providers/memories_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; +import 'package:omi/utils/ui_guidelines.dart'; import 'package:omi/widgets/extensions/string.dart'; import 'delete_confirmation.dart'; +import 'category_chip.dart'; class MemoryItem extends StatelessWidget { final Memory memory; @@ -25,24 +27,36 @@ class MemoryItem extends StatelessWidget { final Widget memoryWidget = GestureDetector( onTap: () => onTap(context, memory, provider), child: Container( - margin: const EdgeInsets.only(bottom: 8), - decoration: BoxDecoration( - color: Colors.grey.shade900, - borderRadius: BorderRadius.circular(12), - ), + margin: const EdgeInsets.only(bottom: AppStyles.spacingM), + decoration: AppStyles.cardDecoration, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ListTile( - contentPadding: const EdgeInsets.fromLTRB(16, 8, 16, 8), - title: Text( - memory.content.decodeString, - style: const TextStyle( - color: Colors.white, - fontSize: 16, - ), + Padding( + padding: const EdgeInsets.all(AppStyles.spacingL), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Expanded( + child: CategoryChip( + category: memory.category, + showIcon: true, + ), + ), + _buildVisibilityButton(context), + ], + ), + const SizedBox(height: AppStyles.spacingM), + Text( + memory.content.decodeString, + style: AppStyles.body, + ), + ], ), - trailing: _buildVisibilityButton(context), ), ], ), @@ -65,10 +79,10 @@ class MemoryItem extends StatelessWidget { MixpanelManager().memoriesPageDeletedMemory(memory); }, background: Container( - margin: const EdgeInsets.only(bottom: 8), + margin: const EdgeInsets.only(bottom: AppStyles.spacingM), decoration: BoxDecoration( - color: Colors.red.shade900, - borderRadius: BorderRadius.circular(12), + color: AppStyles.error, + borderRadius: BorderRadius.circular(AppStyles.radiusLarge), ), alignment: Alignment.centerRight, padding: const EdgeInsets.only(right: 20), @@ -83,19 +97,21 @@ class MemoryItem extends StatelessWidget { padding: EdgeInsets.zero, position: PopupMenuPosition.under, surfaceTintColor: Colors.transparent, - color: Colors.grey.shade800, + color: AppStyles.backgroundTertiary, shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(AppStyles.radiusLarge), ), offset: const Offset(0, 4), child: Container( - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + height: 26, + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(AppStyles.radiusSmall), ), child: Row( mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( memory.visibility == MemoryVisibility.private ? Icons.lock_outline : Icons.public, diff --git a/app/lib/pages/memories/widgets/memory_management_sheet.dart b/app/lib/pages/memories/widgets/memory_management_sheet.dart new file mode 100644 index 000000000..a90c8103e --- /dev/null +++ b/app/lib/pages/memories/widgets/memory_management_sheet.dart @@ -0,0 +1,280 @@ +import 'package:flutter/material.dart'; +import 'package:omi/providers/memories_provider.dart'; +import 'package:omi/utils/ui_guidelines.dart'; + +class MemoryManagementSheet extends StatelessWidget { + final MemoriesProvider provider; + + const MemoryManagementSheet({ + super.key, + required this.provider, + }); + + @override + Widget build(BuildContext context) { + return Container( + decoration: BoxDecoration( + color: AppStyles.backgroundSecondary, + borderRadius: const BorderRadius.vertical(top: Radius.circular(20)), + ), + child: SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _buildHeader(context), + const Divider(height: 1, color: Colors.white10), + _buildMemoryCount(context), + _buildActionButtons(context), + ], + ), + ), + ); + } + + Widget _buildHeader(BuildContext context) { + return Padding( + padding: const EdgeInsets.fromLTRB(20, 16, 16, 16), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + const Text( + 'Memory Management', + style: AppStyles.subtitle, + ), + IconButton( + icon: const Icon(Icons.close, color: Colors.white70), + onPressed: () => Navigator.pop(context), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), + ), + ], + ), + ); + } + + Widget _buildMemoryCount(BuildContext context) { + final totalMemories = provider.memories.length; + final publicMemories = provider.memories.where((m) => !m.deleted && m.visibility.name == 'public').length; + final privateMemories = provider.memories.where((m) => !m.deleted && m.visibility.name == 'private').length; + + return Container( + width: double.infinity, + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + 'You have $totalMemories total memories', + style: AppStyles.body, + ), + const SizedBox(height: 8), + _buildMemoryCountRow(Icons.public, 'Public memories', publicMemories), + const SizedBox(height: 4), + _buildMemoryCountRow(Icons.lock_outline, 'Private memories', privateMemories), + ], + ), + ); + } + + Widget _buildMemoryCountRow(IconData icon, String label, int count) { + return Row( + children: [ + Icon(icon, size: 16, color: Colors.white60), + const SizedBox(width: 8), + Text( + label, + style: AppStyles.caption, + ), + const Spacer(), + Text( + count.toString(), + style: AppStyles.caption.copyWith( + fontWeight: FontWeight.w600, + ), + ), + ], + ); + } + + Widget _buildActionButtons(BuildContext context) { + return Padding( + padding: const EdgeInsets.all(20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + _buildActionButton( + context, + 'Make All Memories Private', + Icons.lock_outline, + Colors.white.withOpacity(0.1), + () => _makeAllMemoriesPrivate(context), + ), + const SizedBox(height: 12), + _buildActionButton( + context, + 'Make All Memories Public', + Icons.public, + Colors.white.withOpacity(0.1), + () => _makeAllMemoriesPublic(context), + ), + const SizedBox(height: 24), + const Divider(height: 1, color: Colors.white10), + const SizedBox(height: 24), + _buildActionButton( + context, + 'Delete All Memories', + Icons.delete_outline, + Colors.red.withOpacity(0.1), + () => _confirmDeleteAllMemories(context), + textColor: Colors.red, + iconColor: Colors.red, + ), + const SizedBox(height: 12), + ], + ), + ); + } + + Widget _buildActionButton( + BuildContext context, + String text, + IconData icon, + Color backgroundColor, + VoidCallback onPressed, { + Color textColor = Colors.white, + Color iconColor = Colors.white, + }) { + return ElevatedButton( + onPressed: onPressed, + style: ElevatedButton.styleFrom( + backgroundColor: backgroundColor, + foregroundColor: textColor, + elevation: 0, + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + child: Row( + children: [ + Icon(icon, size: 20, color: iconColor), + const SizedBox(width: 12), + Text( + text, + style: TextStyle( + color: textColor, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + ], + ), + ); + } + + void _makeAllMemoriesPrivate(BuildContext context) async { + Navigator.pop(context); + await provider.updateAllMemoriesVisibility(true); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('All memories are now private'), + backgroundColor: AppStyles.backgroundTertiary, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + margin: const EdgeInsets.fromLTRB(16, 0, 16, 16), + duration: const Duration(seconds: 2), + ), + ); + } + } + + void _makeAllMemoriesPublic(BuildContext context) async { + Navigator.pop(context); + await provider.updateAllMemoriesVisibility(false); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('All memories are now public'), + backgroundColor: AppStyles.backgroundTertiary, + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + margin: const EdgeInsets.fromLTRB(16, 0, 16, 16), + duration: const Duration(seconds: 2), + ), + ); + } + } + + void _confirmDeleteAllMemories(BuildContext context) { + if (provider.memories.isEmpty) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('No memories to delete'), + backgroundColor: AppStyles.backgroundTertiary, + duration: const Duration(seconds: 2), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + margin: const EdgeInsets.fromLTRB(16, 0, 16, 16), + ), + ); + Navigator.pop(context); + return; + } + + showDialog( + context: context, + builder: (context) => AlertDialog( + backgroundColor: AppStyles.backgroundSecondary, + title: const Text( + 'Clear Omi\'s Memory', + style: TextStyle(color: Colors.white), + ), + content: Text( + 'Are you sure you want to clear Omi\'s memory? This action cannot be undone.', + style: TextStyle(color: Colors.grey.shade300), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text( + 'Cancel', + style: TextStyle(color: Colors.grey.shade400), + ), + ), + TextButton( + onPressed: () { + provider.deleteAllMemories(); + Navigator.pop(context); // Close dialog + Navigator.pop(context); // Close sheet + ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: const Text('Omi\'s memory about you has been cleared'), + backgroundColor: AppStyles.backgroundTertiary, + duration: const Duration(seconds: 2), + behavior: SnackBarBehavior.floating, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + margin: const EdgeInsets.fromLTRB(16, 0, 16, 16), + ), + ); + }, + child: const Text( + 'Clear Memory', + style: TextStyle(color: Colors.red), + ), + ), + ], + ), + ); + } +} \ No newline at end of file diff --git a/app/lib/pages/memories/widgets/memory_review_sheet.dart b/app/lib/pages/memories/widgets/memory_review_sheet.dart index f0a343464..955a3e2a8 100644 --- a/app/lib/pages/memories/widgets/memory_review_sheet.dart +++ b/app/lib/pages/memories/widgets/memory_review_sheet.dart @@ -25,8 +25,8 @@ class MemoriesReviewSheet extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ Container( - padding: const EdgeInsets.symmetric(horizontal: 18, vertical: 14), - margin: const EdgeInsets.only(bottom: 16), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + margin: const EdgeInsets.only(bottom: 12), child: Column( children: [ Row( @@ -38,11 +38,11 @@ class MemoriesReviewSheet extends StatelessWidget { SizedBox( width: MediaQuery.of(context).size.width * 0.74, child: Text( - 'Review and save ${memories.length} memories generated from today\'s conversation with Omi', + '${memories.length} new memories to review', style: const TextStyle( color: Colors.white, fontSize: 16, - fontWeight: FontWeight.w400, + fontWeight: FontWeight.w500, ), ), ), @@ -51,28 +51,30 @@ class MemoriesReviewSheet extends StatelessWidget { ), IconButton( icon: const Icon(Icons.close, color: Colors.white70), + padding: EdgeInsets.zero, + constraints: const BoxConstraints(), onPressed: () => Navigator.pop(context), ), ], ), - const SizedBox(height: 24), + const SizedBox(height: 20), Row( children: [ Expanded( child: TextButton( style: TextButton.styleFrom( backgroundColor: Colors.white.withOpacity(0.1), - padding: const EdgeInsets.symmetric(vertical: 12), + padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(10), ), ), onPressed: () => Navigator.pop(context), child: Text( - 'Review later', + 'Later', style: TextStyle( color: Colors.grey.shade300, - fontSize: 15, + fontSize: 14, ), ), ), @@ -82,9 +84,9 @@ class MemoriesReviewSheet extends StatelessWidget { child: TextButton( style: TextButton.styleFrom( backgroundColor: Colors.white, - padding: const EdgeInsets.symmetric(vertical: 12), + padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), + borderRadius: BorderRadius.circular(10), ), ), onPressed: () { @@ -100,7 +102,7 @@ class MemoriesReviewSheet extends StatelessWidget { 'Review now', style: TextStyle( color: Colors.black, - fontSize: 15, + fontSize: 14, fontWeight: FontWeight.w600, ), ), diff --git a/app/lib/providers/memories_provider.dart b/app/lib/providers/memories_provider.dart index b8cbcab47..1221f3d71 100644 --- a/app/lib/providers/memories_provider.dart +++ b/app/lib/providers/memories_provider.dart @@ -5,38 +5,51 @@ import 'package:omi/backend/schema/memory.dart'; import 'package:omi/providers/base_provider.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; -class MemoriesProvider extends BaseProvider { - List memories = []; - List filteredMemories = []; +class MemoriesProvider extends ChangeNotifier { + List _memories = []; + List _unreviewed = []; + bool _loading = true; + String _searchQuery = ''; + MemoryCategory? _categoryFilter; List> categories = []; MemoryCategory? selectedCategory; - String searchQuery = ''; - List get unreviewed => memories - .where((f) => !f.reviewed && f.createdAt.isAfter(DateTime.now().subtract(const Duration(days: 1)))) - .toList(); + List get memories => _memories; + List get unreviewed => _unreviewed; + bool get loading => _loading; + String get searchQuery => _searchQuery; + MemoryCategory? get categoryFilter => _categoryFilter; + + List get filteredMemories { + return _memories.where((memory) { + // Apply search filter + final matchesSearch = _searchQuery.isEmpty || + memory.content.decodeString.toLowerCase().contains(_searchQuery.toLowerCase()); + + // Apply category filter + final matchesCategory = _categoryFilter == null || + memory.category == _categoryFilter; + + return matchesSearch && matchesCategory; + }).toList()..sort((a, b) => b.createdAt.compareTo(a.createdAt)); + } void setCategory(MemoryCategory? category) { selectedCategory = category; - _filterMemories(); notifyListeners(); } void setSearchQuery(String query) { - searchQuery = query.toLowerCase(); - _filterMemories(); + _searchQuery = query.toLowerCase(); notifyListeners(); } - void _filterMemories() { - if (searchQuery.isNotEmpty) { - filteredMemories = - memories.where((memory) => memory.content.decodeString.toLowerCase().contains(searchQuery)).toList(); - } else { - filteredMemories = memories; - } - filteredMemories.sort((a, b) => b.createdAt.compareTo(a.createdAt)); + void setCategoryFilter(MemoryCategory? category) { + _categoryFilter = category; + notifyListeners(); } void _setCategories() { @@ -44,7 +57,6 @@ class MemoriesProvider extends BaseProvider { final count = memories.where((memory) => memory.category == category).length; return Tuple2(category, count); }).toList(); - _filterMemories(); notifyListeners(); } @@ -52,85 +64,124 @@ class MemoriesProvider extends BaseProvider { await loadMemories(); } - Future loadMemories() async { - loading = true; + Future loadMemories() async { + _loading = true; notifyListeners(); - memories = await getMemories(); - loading = false; + + _memories = await getMemories(); + _unreviewed = _memories + .where((memory) => !memory.reviewed && memory.createdAt.isAfter(DateTime.now().subtract(const Duration(days: 1)))) + .toList(); + + _loading = false; _setCategories(); } void deleteMemory(Memory memory) async { - deleteMemoryServer(memory.id); - memories.remove(memory); + await deleteMemoryServer(memory.id); + _memories.remove(memory); + _unreviewed.remove(memory); _setCategories(); - notifyListeners(); } void deleteAllMemories() async { - deleteAllMemoriesServer(); - memories.clear(); - filteredMemories.clear(); + await deleteAllMemoriesServer(); + _memories.clear(); + _unreviewed.clear(); _setCategories(); - notifyListeners(); } - void createMemory(String content, [MemoryVisibility visibility = MemoryVisibility.public]) async { - createMemoryServer(content, visibility.name); - memories.add(Memory( + void createMemory(String content, [MemoryVisibility visibility = MemoryVisibility.public, MemoryCategory category = MemoryCategory.core]) async { + final newMemory = Memory( id: const Uuid().v4(), uid: SharedPreferencesUtil().uid, content: content, - category: MemoryCategory.other, + category: category, createdAt: DateTime.now(), updatedAt: DateTime.now(), - manuallyAdded: true, - edited: false, - reviewed: false, - userReview: null, conversationId: null, - deleted: false, + reviewed: false, + manuallyAdded: true, visibility: visibility, - )); + ); + + await createMemoryServer(content, visibility.name); + _memories.add(newMemory); + _unreviewed.add(newMemory); _setCategories(); } - void updateMemoryVisibility(Memory memory, MemoryVisibility visibility) async { - var idx = memories.indexWhere((f) => f.id == memory.id); - updateMemoryVisibilityServer(memory.id, visibility.name); - memory.visibility = visibility; - memories[idx] = memory; - _setCategories(); + Future updateMemoryVisibility(Memory memory, MemoryVisibility visibility) async { + await updateMemoryVisibilityServer(memory.id, visibility.name); + + final idx = _memories.indexWhere((m) => m.id == memory.id); + if (idx != -1) { + memory.visibility = visibility; + _memories[idx] = memory; + _unreviewed.remove(memory); + _setCategories(); + } } void editMemory(Memory memory, String value, [MemoryCategory? category]) async { - var idx = memories.indexWhere((f) => f.id == memory.id); - editMemoryServer(memory.id, value); - memory.content = value; - if (category != null) { - memory.category = category; + await editMemoryServer(memory.id, value); + + final idx = _memories.indexWhere((m) => m.id == memory.id); + if (idx != -1) { + memory.content = value; + if (category != null) { + memory.category = category; + } + memory.updatedAt = DateTime.now(); + memory.edited = true; + _memories[idx] = memory; + + // Remove from unreviewed if it was there + final unreviewedIdx = _unreviewed.indexWhere((m) => m.id == memory.id); + if (unreviewedIdx != -1) { + _unreviewed.removeAt(unreviewedIdx); + } + + _setCategories(); } - memory.updatedAt = DateTime.now(); - memory.edited = true; - memories[idx] = memory; - _setCategories(); } void reviewMemory(Memory memory, bool approved) async { - var idx = memories.indexWhere((f) => f.id == memory.id); + await reviewMemoryServer(memory.id, approved); + + final idx = _memories.indexWhere((m) => m.id == memory.id); if (idx != -1) { memory.reviewed = true; memory.userReview = approved; + if (!approved) { memory.deleted = true; - memories.removeAt(idx); - deleteMemory(memory); + _memories.removeAt(idx); + _unreviewed.remove(memory); + // Don't call deleteMemory again because it would be a duplicate deletion } else { - memories[idx] = memory; - reviewMemoryServer(memory.id, approved); + _memories[idx] = memory; + + // Remove from unreviewed list + final unreviewedIdx = _unreviewed.indexWhere((m) => m.id == memory.id); + if (unreviewedIdx != -1) { + _unreviewed.removeAt(unreviewedIdx); + } } + _setCategories(); - notifyListeners(); } } + + Future updateAllMemoriesVisibility(bool makePrivate) async { + final visibility = makePrivate ? MemoryVisibility.private : MemoryVisibility.public; + + for (var memory in _memories) { + if (memory.visibility != visibility) { + await updateMemoryVisibility(memory, visibility); + } + } + + notifyListeners(); + } } diff --git a/app/lib/utils/ui_guidelines.dart b/app/lib/utils/ui_guidelines.dart new file mode 100644 index 000000000..29091168f --- /dev/null +++ b/app/lib/utils/ui_guidelines.dart @@ -0,0 +1,164 @@ +import 'package:flutter/material.dart'; + +/// UI Guidelines to ensure consistent styling throughout the app +/// Use this class for reference when creating new UI components +class AppStyles { + // Text Styles + static const TextStyle title = TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + color: Colors.white, + ); + + static const TextStyle subtitle = TextStyle( + fontSize: 16, + fontWeight: FontWeight.w500, + color: Colors.white, + ); + + static const TextStyle body = TextStyle( + fontSize: 15, + height: 1.4, + color: Colors.white, + ); + + static const TextStyle caption = TextStyle( + fontSize: 14, + color: Colors.white70, + ); + + static const TextStyle small = TextStyle( + fontSize: 12, + color: Colors.white70, + ); + + static const TextStyle label = TextStyle( + fontSize: 12, + fontWeight: FontWeight.w500, + color: Colors.white70, + ); + + // Colors + static final Color backgroundPrimary = Colors.black; + static final Color backgroundSecondary = Colors.grey.shade900; + static final Color backgroundTertiary = Colors.grey.shade800; + + static const Color textPrimary = Colors.white; + static final Color textSecondary = Colors.white.withOpacity(0.8); + static final Color textTertiary = Colors.white.withOpacity(0.6); + + static const Color accent = Colors.blue; + static final Color error = Colors.red.shade800; + static final Color success = Colors.green.shade600; + + // Spacing + static const double spacingXS = 4.0; + static const double spacingS = 8.0; + static const double spacingM = 12.0; + static const double spacingL = 16.0; + static const double spacingXL = 24.0; + static const double spacingXXL = 32.0; + + // Radius + static const double radiusSmall = 6.0; + static const double radiusMedium = 8.0; + static const double radiusLarge = 12.0; + static const double radiusCircular = 100.0; + + // Widget specific + static final cardDecoration = BoxDecoration( + color: backgroundSecondary, + borderRadius: BorderRadius.circular(radiusLarge), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], + ); + + static final inputDecoration = InputDecoration( + filled: true, + fillColor: backgroundTertiary, + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(radiusMedium), + borderSide: BorderSide.none, + ), + ); + + static final chipDecoration = BoxDecoration( + color: backgroundTertiary.withOpacity(0.6), + borderRadius: BorderRadius.circular(radiusCircular), + ); +} + +/// Theme extension to provide app styles as part of the theme +class AppTheme extends ThemeExtension { + final TextStyle title; + final TextStyle subtitle; + final TextStyle body; + final TextStyle caption; + final TextStyle small; + final TextStyle label; + + AppTheme({ + required this.title, + required this.subtitle, + required this.body, + required this.caption, + required this.small, + required this.label, + }); + + @override + ThemeExtension copyWith({ + TextStyle? title, + TextStyle? subtitle, + TextStyle? body, + TextStyle? caption, + TextStyle? small, + TextStyle? label, + }) { + return AppTheme( + title: title ?? this.title, + subtitle: subtitle ?? this.subtitle, + body: body ?? this.body, + caption: caption ?? this.caption, + small: small ?? this.small, + label: label ?? this.label, + ); + } + + @override + ThemeExtension lerp(ThemeExtension? other, double t) { + if (other is! AppTheme) { + return this; + } + return AppTheme( + title: TextStyle.lerp(title, other.title, t)!, + subtitle: TextStyle.lerp(subtitle, other.subtitle, t)!, + body: TextStyle.lerp(body, other.body, t)!, + caption: TextStyle.lerp(caption, other.caption, t)!, + small: TextStyle.lerp(small, other.small, t)!, + label: TextStyle.lerp(label, other.label, t)!, + ); + } + + /// Apply AppTheme to ThemeData + static ThemeData applyToTheme(ThemeData theme) { + return theme.copyWith( + extensions: [ + AppTheme( + title: AppStyles.title, + subtitle: AppStyles.subtitle, + body: AppStyles.body, + caption: AppStyles.caption, + small: AppStyles.small, + label: AppStyles.label, + ), + ], + ); + } +} \ No newline at end of file From 28aabaf3d6a98d3f77a7061670bee4a7bfbf32b7 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Sun, 11 May 2025 17:44:27 +0400 Subject: [PATCH 010/213] =?UTF-8?q?Polished=20up=20the=20profile=20&=20set?= =?UTF-8?q?tings:=20=09=E2=80=A2=09Made=20nav=20from=20settings=20to=20per?= =?UTF-8?q?sona=20profile=20smooth.=20=09=E2=80=A2=09Cleaned=20up=20the=20?= =?UTF-8?q?back=20button=20logic.=20=09=E2=80=A2=09Settings=20page=20got?= =?UTF-8?q?=20a=20layout=20revamp=20+=20quick=20link=20to=20persona.=20=09?= =?UTF-8?q?=E2=80=A2=09Profile=20page=20looks=20sharper=20=E2=80=94=20new?= =?UTF-8?q?=20headers,=20tidy=20tiles.=20=09=E2=80=A2=09Refactored=20widge?= =?UTF-8?q?ts=20to=20be=20less=20messy.=20=09=E2=80=A2=09Hooked=20up=20Mix?= =?UTF-8?q?panel=20to=20track=20memory=20page=20moves.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/lib/pages/persona/persona_profile.dart | 133 ++----- app/lib/pages/settings/page.dart | 119 ++++-- app/lib/pages/settings/profile.dart | 426 ++++++++++----------- app/lib/pages/settings/widgets.dart | 42 +- app/lib/utils/analytics/mixpanel.dart | 2 + 5 files changed, 364 insertions(+), 358 deletions(-) diff --git a/app/lib/pages/persona/persona_profile.dart b/app/lib/pages/persona/persona_profile.dart index 801b3a508..f9b9599ff 100644 --- a/app/lib/pages/persona/persona_profile.dart +++ b/app/lib/pages/persona/persona_profile.dart @@ -46,6 +46,13 @@ class _PersonaProfilePageState extends State { void initState() { WidgetsBinding.instance.addPostFrameCallback((_) async { final provider = Provider.of(context, listen: false); + + // Check if we came from settings + final isFromSettings = ModalRoute.of(context)?.settings.arguments == 'from_settings'; + if (isFromSettings) { + provider.setRouting(PersonaProfileRouting.home); + } + if (provider.routing == PersonaProfileRouting.apps_updates && provider.userPersona != null) { provider.prepareUpdatePersona(provider.userPersona!); } else { @@ -71,95 +78,37 @@ class _PersonaProfilePageState extends State { backgroundColor: Colors.transparent, appBar: AppBar( backgroundColor: Colors.transparent, - leading: Consumer(builder: (context, personaProvider, _) { - return personaProvider.routing == PersonaProfileRouting.apps_updates - ? IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pop(context); - }, - ) - : GestureDetector( - onTap: () async { - if (personaProvider.routing == PersonaProfileRouting.no_device) { - routeToPage(context, const CloneChatPage(), replace: false); - } else { - context.read().setIndex(1); - if (context.read().onSelectedIndexChanged != null) { - context.read().onSelectedIndexChanged!(1); - } - var appId = persona!.id; - var appProvider = Provider.of(context, listen: false); - var messageProvider = Provider.of(context, listen: false); - App? selectedApp; - if (appId.isNotEmpty) { - selectedApp = await appProvider.getAppFromId(appId); - } - appProvider.setSelectedChatAppId(appId); - await messageProvider.refreshMessages(); - if (messageProvider.messages.isEmpty) { - messageProvider.sendInitialAppMessage(selectedApp); - } - } - }, - child: Padding( - padding: const EdgeInsets.all(16.0), - child: SvgPicture.asset( - Assets.images.icCloneChat.path, - width: 24, - height: 24, - ), - ), - ); - }), - actions: [ - // Only show settings icon for create_my_clone or home routing - Consumer(builder: (context, personaProvider, _) { - if (personaProvider.routing == PersonaProfileRouting.no_device) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: GestureDetector( - onTap: () async { - await routeToPage(context, const SettingsPage(mode: SettingsMode.no_device)); - }, - child: SvgPicture.asset( - Assets.images.icSettingPersona.path, - width: 44, - height: 44, - ), - ), - ); - } - if (personaProvider.routing == PersonaProfileRouting.create_my_clone || - personaProvider.routing == PersonaProfileRouting.home) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: GestureDetector( - onTap: () async { - MixpanelManager().pageOpened('Settings'); - String language = SharedPreferencesUtil().userPrimaryLanguage; - bool hasSpeech = SharedPreferencesUtil().hasSpeakerProfile; - String transcriptModel = SharedPreferencesUtil().transcriptionModel; - await routeToPage(context, const SettingsPage()); - if (language != SharedPreferencesUtil().userPrimaryLanguage || - hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || - transcriptModel != SharedPreferencesUtil().transcriptionModel) { - if (context.mounted) { - context.read().onRecordProfileSettingChanged(); - } - } - }, - child: SvgPicture.asset( - Assets.images.icSettingPersona.path, - width: 44, - height: 44, - ), - ), - ); + leading: IconButton( + icon: const Icon(Icons.arrow_back, color: Colors.white), + onPressed: () { + final isFromSettings = ModalRoute.of(context)?.settings.arguments == 'from_settings'; + + if (isFromSettings) { + // If we came from settings, just pop back to it + Navigator.pop(context); + } else if (provider.routing == PersonaProfileRouting.apps_updates) { + // Regular back for apps updates flow + Navigator.pop(context); + } else { + // For main app navigation + var homeProvider = Provider.of(context, listen: false); + homeProvider.setIndex(0); // Go back to home tab + if (homeProvider.onSelectedIndexChanged != null) { + homeProvider.onSelectedIndexChanged!(0); + } } - return const SizedBox.shrink(); - }), - ], + }, + ), + title: const Text( + 'Persona', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.w600, + color: Colors.white, + ), + ), + centerTitle: true, + actions: [], // Empty actions - no settings button needed ), body: persona == null ? const Center( @@ -738,6 +687,8 @@ class _PersonaProfilePageState extends State { bool isComingSoon = false, bool showConnect = false, }) { + final Color grayedOutColor = Colors.grey[600]!; + return Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), decoration: BoxDecoration( @@ -759,7 +710,7 @@ class _PersonaProfilePageState extends State { Text( text, style: TextStyle( - color: isComingSoon ? Colors.grey[600] : Colors.white, + color: isComingSoon ? grayedOutColor : Colors.white, fontSize: 16, ), ), @@ -771,10 +722,10 @@ class _PersonaProfilePageState extends State { color: const Color(0xFF373737), borderRadius: BorderRadius.circular(16), ), - child: const Text( + child: Text( 'Coming soon', style: TextStyle( - color: Colors.white, + color: grayedOutColor, fontSize: 12, ), ), diff --git a/app/lib/pages/settings/page.dart b/app/lib/pages/settings/page.dart index 8d50db0b5..5d16015db 100644 --- a/app/lib/pages/settings/page.dart +++ b/app/lib/pages/settings/page.dart @@ -3,15 +3,20 @@ import 'package:omi/backend/auth.dart'; import 'package:omi/backend/preferences.dart'; import 'package:omi/main.dart'; import 'package:omi/pages/persona/persona_provider.dart'; +import 'package:omi/pages/persona/persona_profile.dart'; import 'package:omi/pages/settings/about.dart'; import 'package:omi/pages/settings/developer.dart'; import 'package:omi/pages/settings/profile.dart'; import 'package:omi/pages/settings/widgets.dart'; +import 'package:omi/providers/home_provider.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:omi/widgets/dialog.dart'; import 'package:intercom_flutter/intercom_flutter.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:omi/gen/assets.gen.dart'; +import 'package:omi/providers/capture_provider.dart'; import 'device_settings.dart'; @@ -56,23 +61,19 @@ class _SettingsPageState extends State { bool loadingExportMemories = false; Widget _buildOmiModeContent(BuildContext context) { + // Group settings by category: Account, Device, Support, Info, Actions return Column( children: [ - const SizedBox(height: 32.0), - getItemAddOn2( - 'Need Help? Chat with us', - () async { - await Intercom.instance.displayMessenger(); - }, - icon: Icons.chat, - ), - const SizedBox(height: 20), + const SizedBox(height: 24.0), + // Account Settings getItemAddOn2( 'Profile', () => routeToPage(context, const ProfilePage()), icon: Icons.person, ), - const SizedBox(height: 20), + const SizedBox(height: 12), + + // Device Settings getItemAddOn2( 'Device Settings', () { @@ -84,7 +85,16 @@ class _SettingsPageState extends State { }, icon: Icons.bluetooth_connected_sharp, ), - const SizedBox(height: 8), + const SizedBox(height: 12), + + // Advanced Settings + getItemAddOn2('Developer Mode', () async { + await routeToPage(context, const DeveloperSettingsPage()); + setState(() {}); + }, icon: Icons.code), + const SizedBox(height: 12), + + // Help & Support getItemAddOn2( 'Guides & Tutorials', () async { @@ -92,18 +102,25 @@ class _SettingsPageState extends State { }, icon: Icons.help_outline_outlined, ), - const SizedBox(height: 20), + const SizedBox(height: 12), + getItemAddOn2( + 'Need Help? Chat with us', + () async { + await Intercom.instance.displayMessenger(); + }, + icon: Icons.chat, + ), + const SizedBox(height: 12), + + // Information getItemAddOn2( 'About Omi', () => routeToPage(context, const AboutOmiPage()), - icon: Icons.workspace_premium_sharp, + icon: Icons.info_outline, ), - const SizedBox(height: 8), - getItemAddOn2('Developer Mode', () async { - await routeToPage(context, const DeveloperSettingsPage()); - setState(() {}); - }, icon: Icons.code), - const SizedBox(height: 32), + const SizedBox(height: 24), + + // Actions getItemAddOn2('Sign Out', () async { await showDialog( context: context, @@ -120,18 +137,20 @@ class _SettingsPageState extends State { }, ); }, icon: Icons.logout), - const SizedBox(height: 24), + const SizedBox(height: 20), + + // Version Info Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Align( alignment: Alignment.center, child: Text( 'Version: $version+$buildVersion', - style: const TextStyle(color: Color.fromARGB(255, 150, 150, 150), fontSize: 16), + style: const TextStyle(color: Color.fromARGB(255, 150, 150, 150), fontSize: 14), ), ), ), - const SizedBox(height: 32), + const SizedBox(height: 24), ], ); } @@ -139,7 +158,9 @@ class _SettingsPageState extends State { Widget _buildNoDeviceModeContent(BuildContext context) { return Column( children: [ - const SizedBox(height: 32.0), + const SizedBox(height: 24.0), + + // Help & Support getItemAddOn2( 'Need Help? Chat with us', () async { @@ -147,7 +168,9 @@ class _SettingsPageState extends State { }, icon: Icons.chat, ), - const SizedBox(height: 32), + const SizedBox(height: 24), + + // Actions getItemAddOn2('Sign Out', () async { await showDialog( context: context, @@ -165,18 +188,20 @@ class _SettingsPageState extends State { }, ); }, icon: Icons.logout), - const SizedBox(height: 24), + const SizedBox(height: 20), + + // Version Info Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: Align( alignment: Alignment.center, child: Text( 'Version: $version+$buildVersion', - style: const TextStyle(color: Color.fromARGB(255, 150, 150, 150), fontSize: 16), + style: const TextStyle(color: Color.fromARGB(255, 150, 150, 150), fontSize: 14), ), ), ), - const SizedBox(height: 32), + const SizedBox(height: 24), ], ); } @@ -190,14 +215,50 @@ class _SettingsPageState extends State { appBar: AppBar( backgroundColor: Theme.of(context).colorScheme.primary, automaticallyImplyLeading: true, - title: const Text('Settings'), - centerTitle: false, + title: const Text( + 'Settings', + style: TextStyle( + fontSize: 22, + fontWeight: FontWeight.w600, + ), + ), + centerTitle: true, leading: IconButton( icon: const Icon(Icons.arrow_back_ios_new), onPressed: () { Navigator.pop(context); }, ), + actions: [ + Consumer(builder: (context, personaProvider, _) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), + child: Container( + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.transparent, + ), + child: GestureDetector( + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PersonaProfilePage(), + settings: const RouteSettings( + arguments: 'from_settings', + ), + ), + ); + }, + child: SvgPicture.asset( + Assets.images.icPersonaProfile.path, + width: 28, + height: 28, + ), + ), + ), + ); + }), + ], elevation: 0, ), body: SingleChildScrollView( diff --git a/app/lib/pages/settings/profile.dart b/app/lib/pages/settings/profile.dart index 1453b891c..1ff31daad 100644 --- a/app/lib/pages/settings/profile.dart +++ b/app/lib/pages/settings/profile.dart @@ -23,78 +23,152 @@ class ProfilePage extends StatefulWidget { } class _ProfilePageState extends State { - // Future _checkRecordingPermission() async { - // final permission = await getStoreRecordingPermission(); - // if (mounted) { - // setState(() { - // if (permission != null) { - // SharedPreferencesUtil().permissionStoreRecordingsEnabled = permission; - // } else { - // SharedPreferencesUtil().permissionStoreRecordingsEnabled = false; - // } - // }); - // } - // } - @override void initState() { - // _checkRecordingPermission(); super.initState(); } + Widget _buildSectionHeader(String title) { + return Padding( + padding: const EdgeInsets.only(top: 18, bottom: 8), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + title, + style: const TextStyle( + color: Color(0xFFE0E0E0), + fontSize: 14, + fontWeight: FontWeight.w600, + letterSpacing: 1.2, + ), + ), + ), + ); + } + + Widget _buildProfileTile({ + required String title, + required String subtitle, + required IconData icon, + required VoidCallback onTap, + Color iconColor = Colors.white, + }) { + return Container( + margin: const EdgeInsets.only(bottom: 8), + decoration: BoxDecoration( + color: const Color(0xFF1D1D1D), + borderRadius: BorderRadius.circular(10), + ), + child: ListTile( + dense: true, + contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), + title: Text( + title, + style: const TextStyle( + color: Colors.white, + fontSize: 15, + fontWeight: FontWeight.w500, + ), + ), + subtitle: Text( + subtitle, + style: const TextStyle( + color: Color(0xFFAAAAAA), + fontSize: 13, + ), + ), + trailing: Icon(icon, size: 20, color: iconColor), + onTap: onTap, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ); + } + + Widget _buildPreferenceToggle({ + required String title, + required bool value, + required Function(bool) onChanged, + required VoidCallback onInfoTap, + }) { + return Container( + margin: const EdgeInsets.only(bottom: 8), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), + decoration: BoxDecoration( + color: const Color(0xFF1D1D1D), + borderRadius: BorderRadius.circular(10), + ), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: GestureDetector( + onTap: onInfoTap, + child: Text( + title, + style: const TextStyle( + color: Color(0xFFAAAAAA), + fontSize: 14, + decoration: TextDecoration.underline, + ), + ), + ), + ), + const SizedBox(width: 16), + GestureDetector( + onTap: () => onChanged(!value), + child: Container( + decoration: BoxDecoration( + color: value ? const Color(0xFF4A90E2) : Colors.transparent, + border: Border.all( + color: value ? const Color(0xFF4A90E2) : const Color(0xFFAAAAAA), + width: 2, + ), + borderRadius: BorderRadius.circular(12), + ), + width: 20, + height: 20, + child: value + ? const Icon( + Icons.check, + color: Colors.white, + size: 16, + ) + : null, + ), + ), + ], + ), + ); + } + @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Theme.of(context).colorScheme.primary, appBar: AppBar( - title: const Text('Profile'), + title: const Text( + 'Profile', + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.w600, + ), + ), + centerTitle: true, backgroundColor: Theme.of(context).colorScheme.primary, + elevation: 0, ), body: Padding( - padding: const EdgeInsets.fromLTRB(16, 16, 4, 16), + padding: const EdgeInsets.fromLTRB(16, 8, 16, 16), child: ListView( children: [ - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: const Text('Identifying Others', style: TextStyle(color: Colors.white)), - subtitle: const Text('Tell Omi who said it 🗣️'), - trailing: const Icon(Icons.people, size: 20), - onTap: () { - routeToPage(context, const UserPeoplePage()); - }, - ), - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: Text( - SharedPreferencesUtil().givenName.isEmpty - ? 'About YOU' - : 'About ${SharedPreferencesUtil().givenName.toUpperCase()}', - style: const TextStyle(color: Colors.white)), - subtitle: const Text('What Omi has learned about you 👀'), - trailing: const Icon(Icons.self_improvement, size: 20), - onTap: () { - routeToPage(context, const MemoriesPage()); - MixpanelManager().pageOpened('Profile Facts'); - }, - ), - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: const Text('Speech Profile', style: TextStyle(color: Colors.white)), - subtitle: const Text('Teach Omi your voice'), - trailing: const Icon(Icons.multitrack_audio, size: 20), - onTap: () { - routeToPage(context, const SpeechProfilePage()); - MixpanelManager().pageOpened('Profile Speech Profile'); - }, - ), - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: Text( - SharedPreferencesUtil().givenName.isEmpty ? 'Set Your Name' : 'Change Your Name', - style: const TextStyle(color: Colors.white), - ), - subtitle: Text(SharedPreferencesUtil().givenName.isEmpty ? 'Not set' : SharedPreferencesUtil().givenName), - trailing: const Icon(Icons.person, size: 20), + // YOUR INFORMATION SECTION + _buildSectionHeader('YOUR INFORMATION'), + _buildProfileTile( + title: SharedPreferencesUtil().givenName.isEmpty ? 'Set Your Name' : 'Change Your Name', + subtitle: SharedPreferencesUtil().givenName.isEmpty ? 'Not set' : SharedPreferencesUtil().givenName, + icon: Icons.person, onTap: () async { MixpanelManager().pageOpened('Profile Change Name'); await showDialog( @@ -114,202 +188,100 @@ class _ProfilePageState extends State { ) .key : 'Not set'; - - return ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: const Text('Primary Language', style: TextStyle(color: Colors.white)), - subtitle: Text(languageName), - trailing: const Icon(Icons.language, size: 20), + + return _buildProfileTile( + title: 'Primary Language', + subtitle: languageName, + icon: Icons.language, onTap: () async { MixpanelManager().pageOpened('Profile Change Language'); - // Force the dialog to show even if the user has already set a language await LanguageSelectionDialog.show(context, isRequired: false, forceShow: true); - // Refresh the UI after language is updated await homeProvider.setupUserPrimaryLanguage(); setState(() {}); }, ); }, ), - const SizedBox(height: 56), - const Align( - alignment: Alignment.centerLeft, - child: Text( - 'CREATORS', - style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500), - textAlign: TextAlign.start, - ), + + // VOICE & PEOPLE SECTION + _buildSectionHeader('VOICE & PEOPLE'), + _buildProfileTile( + title: 'Speech Profile', + subtitle: 'Teach Omi your voice', + icon: Icons.multitrack_audio, + onTap: () { + routeToPage(context, const SpeechProfilePage()); + MixpanelManager().pageOpened('Profile Speech Profile'); + }, ), - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: const Text('Payments', style: TextStyle(color: Colors.white)), - subtitle: const Text('Add or change your payment method'), - trailing: const Icon(Icons.attach_money_outlined, size: 20), + _buildProfileTile( + title: 'Identifying Others', + subtitle: 'Tell Omi who said it 🗣️', + icon: Icons.people, onTap: () { - routeToPage(context, const PaymentsPage()); - // MixpanelManager().pageOpened('Profile Connect Stripe'); + routeToPage(context, const UserPeoplePage()); }, ), - const SizedBox(height: 56), - const Align( - alignment: Alignment.centerLeft, - child: Text( - 'PREFERENCES', - style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500), - textAlign: TextAlign.start, - ), + _buildProfileTile( + title: 'Memories', + subtitle: 'What Omi has learned about you 👀', + icon: Icons.self_improvement, + onTap: () { + routeToPage(context, const MemoriesPage()); + MixpanelManager().pageOpened('Profile Facts'); + }, ), - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - child: InkWell( - onTap: () { - setState(() { - SharedPreferencesUtil().optInAnalytics = !SharedPreferencesUtil().optInAnalytics; - SharedPreferencesUtil().optInAnalytics - ? MixpanelManager().optInTracking() - : MixpanelManager().optOutTracking(); - }); - }, - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 12.0), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Expanded( - child: GestureDetector( - onTap: () { - routeToPage(context, const PrivacyInfoPage()); - MixpanelManager().pageOpened('Share Analytics Data Details'); - }, - child: const Text( - 'Help improve Omi by sharing anonymized analytics data', - style: TextStyle( - color: Colors.grey, - fontSize: 16, - decoration: TextDecoration.underline, - ), - ), - ), - ), - const SizedBox( - width: 16, - ), - Container( - decoration: BoxDecoration( - color: SharedPreferencesUtil().optInAnalytics - ? const Color.fromARGB(255, 150, 150, 150) - : Colors.transparent, // Fill color when checked - border: Border.all( - color: const Color.fromARGB(255, 150, 150, 150), - width: 2, - ), - borderRadius: BorderRadius.circular(12), - ), - width: 22, - height: 22, - child: SharedPreferencesUtil().optInAnalytics // Show the icon only when checked - ? const Icon( - Icons.check, - color: Colors.white, // Tick color - size: 18, - ) - : null, // No icon when unchecked - ), - ], - ), - ), - ), + + // PAYMENT SECTION + _buildSectionHeader('PAYMENT'), + _buildProfileTile( + title: 'Payment Methods', + subtitle: 'Add or change your payment method', + icon: Icons.attach_money_outlined, + onTap: () { + routeToPage(context, const PaymentsPage()); + }, ), - // Padding( - // padding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - // child: InkWell( - // onTap: () { - // routeToPage(context, const RecordingsStoragePermission()); - // }, - // child: Padding( - // padding: const EdgeInsets.symmetric(vertical: 12.0), - // child: Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // children: [ - // Expanded( - // child: GestureDetector( - // onTap: () { - // routeToPage(context, const RecordingsStoragePermission()); - // }, - // child: const Text( - // 'Allow Omi to store recordings of your conversations', - // style: TextStyle( - // color: Colors.grey, - // fontSize: 16, - // decoration: TextDecoration.underline, - // ), - // ), - // ), - // ), - // const SizedBox( - // width: 16, - // ), - // Container( - // decoration: BoxDecoration( - // color: SharedPreferencesUtil().permissionStoreRecordingsEnabled - // ? const Color.fromARGB(255, 150, 150, 150) - // : Colors.transparent, - // border: Border.all( - // color: const Color.fromARGB(255, 150, 150, 150), - // width: 2, - // ), - // borderRadius: BorderRadius.circular(12), - // ), - // width: 22, - // height: 22, - // child: SharedPreferencesUtil().permissionStoreRecordingsEnabled - // ? const Icon( - // Icons.check, - // color: Colors.white, - // size: 18, - // ) - // : null, - // ), - // ], - // ), - // ), - // ), - // ), - const SizedBox(height: 32), - // Divider(color: Colors.grey.shade300, height: 1), - const SizedBox(height: 24), - const Align( - alignment: Alignment.centerLeft, - child: Text( - 'OTHER', - style: TextStyle(color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500), - textAlign: TextAlign.start, - ), + + // PREFERENCES SECTION + _buildSectionHeader('PREFERENCES'), + _buildPreferenceToggle( + title: 'Help improve Omi by sharing anonymized analytics data', + value: SharedPreferencesUtil().optInAnalytics, + onChanged: (value) { + setState(() { + SharedPreferencesUtil().optInAnalytics = value; + value ? MixpanelManager().optInTracking() : MixpanelManager().optOutTracking(); + }); + }, + onInfoTap: () { + routeToPage(context, const PrivacyInfoPage()); + MixpanelManager().pageOpened('Share Analytics Data Details'); + }, ), - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: const Text('Your User ID', style: TextStyle(color: Colors.white)), - subtitle: Text(SharedPreferencesUtil().uid), - trailing: const Icon(Icons.copy_rounded, size: 20, color: Colors.white), + + // ACCOUNT SECTION + _buildSectionHeader('ACCOUNT'), + _buildProfileTile( + title: 'User ID', + subtitle: SharedPreferencesUtil().uid, + icon: Icons.copy_rounded, onTap: () { Clipboard.setData(ClipboardData(text: SharedPreferencesUtil().uid)); ScaffoldMessenger.of(context) .showSnackBar(const SnackBar(content: Text('User ID copied to clipboard'))); }, ), - ListTile( - contentPadding: const EdgeInsets.fromLTRB(0, 0, 24, 0), - title: const Text('Delete Account', style: TextStyle(color: Colors.white)), - subtitle: const Text('Delete your account and all data'), - trailing: const Icon( - Icons.warning, - size: 20, - ), + _buildProfileTile( + title: 'Delete Account', + subtitle: 'Delete your account and all data', + icon: Icons.warning, + iconColor: Colors.red.shade300, onTap: () { MixpanelManager().pageOpened('Profile Delete Account Dialog'); Navigator.push(context, MaterialPageRoute(builder: (context) => const DeleteAccount())); }, - ) + ), ], ), ), diff --git a/app/lib/pages/settings/widgets.dart b/app/lib/pages/settings/widgets.dart index 7be140a05..a7495b04d 100644 --- a/app/lib/pages/settings/widgets.dart +++ b/app/lib/pages/settings/widgets.dart @@ -53,31 +53,51 @@ getItemAddOn2(String title, VoidCallback onTap, {required IconData icon}) { MixpanelManager().pageOpened('Settings $title'); onTap(); }, - child: Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 0), child: Container( decoration: BoxDecoration( color: const Color.fromARGB(255, 29, 29, 29), - borderRadius: BorderRadius.circular(10.0), + borderRadius: BorderRadius.circular(10.0), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.1), + blurRadius: 4, + offset: const Offset(0, 2), + ), + ], ), child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 16), + padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Row( + Expanded( + child: Row( children: [ - Text( - title, - style: const TextStyle(color: Color.fromARGB(255, 150, 150, 150), fontSize: 16), + Icon( + icon, + color: Colors.white, + size: 22 ), const SizedBox(width: 16), - Icon(icon, color: Colors.white, size: 18), + Expanded( + child: Text( + title, + style: const TextStyle( + color: Colors.white, + fontSize: 16, + fontWeight: FontWeight.w500, + ), + ), + ), ], ), - const Icon(Icons.arrow_forward_ios, color: Colors.white, size: 16), + ), + const Icon( + Icons.arrow_forward_ios, + color: Colors.white, + size: 16 + ), ], - ), ), ), ), diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index 86b71cf0d..6c6c40a62 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -162,6 +162,8 @@ class MixpanelManager { void memoriesPageCreateMemoryBtn() => track('Fact Page Create Fact Button Pressed'); + void memoriesPageReviewBtn() => track('Memories Page Review Button Pressed'); + void memoriesPageCreatedMemory(MemoryCategory category) => track('Fact Page Created Fact', properties: {'fact_category': category.toString().split('.').last}); From 1e2bccdd50eed2b18e2d3b271ac9084c37047907 Mon Sep 17 00:00:00 2001 From: Petr Korolev Date: Sun, 11 May 2025 17:57:35 +0400 Subject: [PATCH 011/213] icon fix --- app/lib/pages/home/page.dart | 156 ++++++++++++++++++++++++----------- 1 file changed, 108 insertions(+), 48 deletions(-) diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index 4ae6ab58d..6180def17 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -392,7 +392,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker margin: const EdgeInsets.fromLTRB(20, 16, 20, 42), decoration: const BoxDecoration( color: Colors.black, - borderRadius: BorderRadius.all(Radius.circular(16)), + borderRadius: BorderRadius.all(Radius.circular(18)), border: GradientBoxBorder( gradient: LinearGradient(colors: [ Color.fromARGB(127, 208, 208, 208), @@ -405,7 +405,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker shape: BoxShape.rectangle, ), child: TabBar( - labelPadding: const EdgeInsets.only(top: 4, bottom: 4), + labelPadding: const EdgeInsets.symmetric(vertical: 8), indicatorPadding: EdgeInsets.zero, onTap: (index) { MixpanelManager() @@ -421,30 +421,66 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker indicatorColor: Colors.transparent, tabs: [ Tab( - child: Text( - 'Home', - style: TextStyle( - color: home.selectedIndex == 0 ? Colors.white : Colors.grey, - fontSize: MediaQuery.sizeOf(context).width < 410 ? 13 : 15, - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.home, + color: home.selectedIndex == 0 ? Colors.white : Colors.grey, + size: 22, + ), + const SizedBox(width: 8), + Text( + 'Home', + style: TextStyle( + color: home.selectedIndex == 0 ? Colors.white : Colors.grey, + fontSize: MediaQuery.sizeOf(context).width < 410 ? 14 : 16, + fontWeight: home.selectedIndex == 0 ? FontWeight.w600 : FontWeight.normal, + ), + ), + ], ), ), Tab( - child: Text( - 'Chat', - style: TextStyle( - color: home.selectedIndex == 1 ? Colors.white : Colors.grey, - fontSize: MediaQuery.sizeOf(context).width < 410 ? 13 : 15, - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.chat_bubble_outline, + color: home.selectedIndex == 1 ? Colors.white : Colors.grey, + size: 22, + ), + const SizedBox(width: 8), + Text( + 'Chat', + style: TextStyle( + color: home.selectedIndex == 1 ? Colors.white : Colors.grey, + fontSize: MediaQuery.sizeOf(context).width < 410 ? 14 : 16, + fontWeight: home.selectedIndex == 1 ? FontWeight.w600 : FontWeight.normal, + ), + ), + ], ), ), Tab( - child: Text( - 'Explore', - style: TextStyle( - color: home.selectedIndex == 2 ? Colors.white : Colors.grey, - fontSize: MediaQuery.sizeOf(context).width < 410 ? 13 : 15, - ), + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon( + Icons.explore_outlined, + color: home.selectedIndex == 2 ? Colors.white : Colors.grey, + size: 22, + ), + const SizedBox(width: 8), + Text( + 'Explore', + style: TextStyle( + color: home.selectedIndex == 2 ? Colors.white : Colors.grey, + fontSize: MediaQuery.sizeOf(context).width < 410 ? 14 : 16, + fontWeight: home.selectedIndex == 2 ? FontWeight.w600 : FontWeight.normal, + ), + ), + ], ), ), ], @@ -484,7 +520,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker }, child: Container( padding: const EdgeInsets.only(left: 12), - child: const Icon(Icons.download, color: Colors.white, size: 24), + child: const Icon(Icons.download, color: Colors.white, size: 28), ), ); } else { @@ -502,16 +538,30 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker controller: _controller!, ); } else if (provider.selectedIndex == 2) { - return Padding( - padding: EdgeInsets.only(right: MediaQuery.sizeOf(context).width * 0.16), - child: const Text('Explore', style: TextStyle(color: Colors.white, fontSize: 18)), + return Center( + child: Padding( + padding: EdgeInsets.only(right: MediaQuery.sizeOf(context).width * 0.10), + child: const Text( + 'Explore', + style: TextStyle( + color: Colors.white, + fontSize: 22, + fontWeight: FontWeight.w600, + ) + ), + ), ); } else { return Expanded( - child: Row( - children: [ - const Spacer(), - ], + child: Center( + child: const Text( + '', + style: TextStyle( + color: Colors.white, + fontSize: 22, + fontWeight: FontWeight.w600, + ), + ), ), ); } @@ -519,27 +569,37 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker ), Row( children: [ - IconButton( - padding: const EdgeInsets.all(8.0), - icon: SvgPicture.asset( - Assets.images.icPersonaProfile.path, - width: 28, - height: 28, + Padding( + padding: const EdgeInsets.only(right: 8.0), + child: Container( + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.transparent, ), - onPressed: () { - MixpanelManager().pageOpened('Persona Profile'); - - // Set routing in provider - var personaProvider = Provider.of(context, listen: false); - personaProvider.setRouting(PersonaProfileRouting.home); - - // Navigate - var homeProvider = Provider.of(context, listen: false); - homeProvider.setIndex(3); - if (homeProvider.onSelectedIndexChanged != null) { - homeProvider.onSelectedIndexChanged!(3); - } - }), + child: IconButton( + padding: const EdgeInsets.all(8.0), + icon: SvgPicture.asset( + Assets.images.icSettingPersona.path, + width: 36, + height: 36, + ), + onPressed: () { + MixpanelManager().pageOpened('Settings'); + String language = SharedPreferencesUtil().userPrimaryLanguage; + bool hasSpeech = SharedPreferencesUtil().hasSpeakerProfile; + String transcriptModel = SharedPreferencesUtil().transcriptionModel; + routeToPage(context, const SettingsPage()); + if (language != SharedPreferencesUtil().userPrimaryLanguage || + hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || + transcriptModel != SharedPreferencesUtil().transcriptionModel) { + if (context.mounted) { + context.read().onRecordProfileSettingChanged(); + } + } + }, + ), + ), + ), ], ), ], From 6efaf4682e0ce5fa31bc0932410cb041f3a82684 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 12:23:09 -0700 Subject: [PATCH 012/213] add mounted checks --- app/lib/pages/apps/widgets/api_keys_widget.dart | 8 +++++--- app/lib/pages/chat/clone_chat_page.dart | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/lib/pages/apps/widgets/api_keys_widget.dart b/app/lib/pages/apps/widgets/api_keys_widget.dart index 845c6bab5..310502e98 100644 --- a/app/lib/pages/apps/widgets/api_keys_widget.dart +++ b/app/lib/pages/apps/widgets/api_keys_widget.dart @@ -40,9 +40,11 @@ class _ApiKeysWidgetState extends State { try { await Provider.of(context, listen: false).loadApiKeys(widget.appId); } finally { - setState(() { - _isLoading = false; - }); + if(mounted){ + setState(() { + _isLoading = false; + }); + } } } diff --git a/app/lib/pages/chat/clone_chat_page.dart b/app/lib/pages/chat/clone_chat_page.dart index cbe624e28..f1752e556 100644 --- a/app/lib/pages/chat/clone_chat_page.dart +++ b/app/lib/pages/chat/clone_chat_page.dart @@ -32,6 +32,10 @@ class CloneChatPageState extends State { if (provider.userPersona != null) { App selectedApp = provider.userPersona!; + if (!mounted){ + return; + } + var appProvider = Provider.of(context, listen: false); SharedPreferencesUtil().appsList = [selectedApp]; appProvider.setApps(); From a30d13dbe3564771daa6f568b7cc3942f0363162 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 12:23:31 -0700 Subject: [PATCH 013/213] check if old app is null --- app/lib/providers/app_provider.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/lib/providers/app_provider.dart b/app/lib/providers/app_provider.dart index 523b41b3a..6164bef0e 100644 --- a/app/lib/providers/app_provider.dart +++ b/app/lib/providers/app_provider.dart @@ -55,7 +55,10 @@ class AppProvider extends BaseProvider { Future getAppDetails(String id) async { var app = await getAppDetailsServer(id); if (app != null) { - var oldApp = apps.where((element) => element.id == id).first; + var oldApp = apps.where((element) => element.id == id).firstOrNull; + if (oldApp == null){ + return null; + } var idx = apps.indexOf(oldApp); apps[idx] = App.fromJson(app); notifyListeners(); From 80709e669e1a1c6251b8dcae90e19442ed1f2dcf Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 12:23:42 -0700 Subject: [PATCH 014/213] check if messageProvder is null --- app/lib/providers/capture_provider.dart | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/app/lib/providers/capture_provider.dart b/app/lib/providers/capture_provider.dart index cdd318148..9f203e772 100644 --- a/app/lib/providers/capture_provider.dart +++ b/app/lib/providers/capture_provider.dart @@ -180,13 +180,15 @@ class CaptureProvider extends ChangeNotifier } BleAudioCodec codec = await _getAudioCodec(_recordingDevice!.id); - await messageProvider?.sendVoiceMessageStreamToServer( - data, - onFirstChunkRecived: () { - _playSpeakerHaptic(deviceId, 2); - }, - codec: codec, - ); + if (messageProvider != null) { + await messageProvider?.sendVoiceMessageStreamToServer( + data, + onFirstChunkRecived: () { + _playSpeakerHaptic(deviceId, 2); + }, + codec: codec, + ); + } } // Just incase the ble connection get loss From 4a592caeff83b2335f239114b74566a8a0db2cb5 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 13:22:12 -0700 Subject: [PATCH 015/213] add memoriesPageReviewBtn event --- app/lib/utils/analytics/mixpanel.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index 86b71cf0d..9da892397 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -162,6 +162,8 @@ class MixpanelManager { void memoriesPageCreateMemoryBtn() => track('Fact Page Create Fact Button Pressed'); + void memoriesPageReviewBtn() => track('Fact page Review Button Pressed'); + void memoriesPageCreatedMemory(MemoryCategory category) => track('Fact Page Created Fact', properties: {'fact_category': category.toString().split('.').last}); From e302d2f30904cd88173414b631ddd31f98b5e6e5 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 13:38:55 -0700 Subject: [PATCH 016/213] don't have to review manually added memories --- app/lib/providers/memories_provider.dart | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/app/lib/providers/memories_provider.dart b/app/lib/providers/memories_provider.dart index 1221f3d71..c7cecbef4 100644 --- a/app/lib/providers/memories_provider.dart +++ b/app/lib/providers/memories_provider.dart @@ -26,15 +26,15 @@ class MemoriesProvider extends ChangeNotifier { List get filteredMemories { return _memories.where((memory) { // Apply search filter - final matchesSearch = _searchQuery.isEmpty || - memory.content.decodeString.toLowerCase().contains(_searchQuery.toLowerCase()); + final matchesSearch = + _searchQuery.isEmpty || memory.content.decodeString.toLowerCase().contains(_searchQuery.toLowerCase()); // Apply category filter - final matchesCategory = _categoryFilter == null || - memory.category == _categoryFilter; + final matchesCategory = _categoryFilter == null || memory.category == _categoryFilter; return matchesSearch && matchesCategory; - }).toList()..sort((a, b) => b.createdAt.compareTo(a.createdAt)); + }).toList() + ..sort((a, b) => b.createdAt.compareTo(a.createdAt)); } void setCategory(MemoryCategory? category) { @@ -70,8 +70,9 @@ class MemoriesProvider extends ChangeNotifier { _memories = await getMemories(); _unreviewed = _memories - .where((memory) => !memory.reviewed && memory.createdAt.isAfter(DateTime.now().subtract(const Duration(days: 1)))) - .toList(); + .where( + (memory) => !memory.reviewed && memory.createdAt.isAfter(DateTime.now().subtract(const Duration(days: 1)))) + .toList(); _loading = false; _setCategories(); @@ -91,7 +92,8 @@ class MemoriesProvider extends ChangeNotifier { _setCategories(); } - void createMemory(String content, [MemoryVisibility visibility = MemoryVisibility.public, MemoryCategory category = MemoryCategory.core]) async { + void createMemory(String content, + [MemoryVisibility visibility = MemoryVisibility.public, MemoryCategory category = MemoryCategory.core]) async { final newMemory = Memory( id: const Uuid().v4(), uid: SharedPreferencesUtil().uid, @@ -107,7 +109,6 @@ class MemoriesProvider extends ChangeNotifier { await createMemoryServer(content, visibility.name); _memories.add(newMemory); - _unreviewed.add(newMemory); _setCategories(); } From 1085bfe93c965dc298e4cef9227a9e49c0222dba Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 13:39:12 -0700 Subject: [PATCH 017/213] change color from blue to purple --- app/lib/pages/memories/memories_review_page.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/pages/memories/memories_review_page.dart b/app/lib/pages/memories/memories_review_page.dart index 5417c64a0..1ab970251 100644 --- a/app/lib/pages/memories/memories_review_page.dart +++ b/app/lib/pages/memories/memories_review_page.dart @@ -321,7 +321,7 @@ class _MemoriesReviewPageState extends State { child: Container( padding: const EdgeInsets.symmetric(vertical: 8), decoration: BoxDecoration( - color: Colors.blue.shade700, + color: Colors.purple.shade700, borderRadius: BorderRadius.circular(8), ), child: const Row( @@ -410,7 +410,7 @@ class _MemoriesReviewPageState extends State { child: Container( padding: const EdgeInsets.symmetric(vertical: 12), decoration: BoxDecoration( - color: Colors.blue.shade700, + color: Colors.purple.shade700, borderRadius: BorderRadius.circular(10), ), alignment: Alignment.center, From b0ce742f8153af1c648ed5ee9e565351d025d95c Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 14:03:21 -0700 Subject: [PATCH 018/213] move personas to the listview --- app/lib/pages/settings/page.dart | 114 ++++++++++++++-------------- app/lib/pages/settings/widgets.dart | 36 ++++----- 2 files changed, 69 insertions(+), 81 deletions(-) diff --git a/app/lib/pages/settings/page.dart b/app/lib/pages/settings/page.dart index 5d16015db..a93ef3319 100644 --- a/app/lib/pages/settings/page.dart +++ b/app/lib/pages/settings/page.dart @@ -8,7 +8,6 @@ import 'package:omi/pages/settings/about.dart'; import 'package:omi/pages/settings/developer.dart'; import 'package:omi/pages/settings/profile.dart'; import 'package:omi/pages/settings/widgets.dart'; -import 'package:omi/providers/home_provider.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:omi/widgets/dialog.dart'; import 'package:intercom_flutter/intercom_flutter.dart'; @@ -16,7 +15,6 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:omi/gen/assets.gen.dart'; -import 'package:omi/providers/capture_provider.dart'; import 'device_settings.dart'; @@ -69,7 +67,27 @@ class _SettingsPageState extends State { getItemAddOn2( 'Profile', () => routeToPage(context, const ProfilePage()), - icon: Icons.person, + icon: const Icon(Icons.person, color: Colors.white, size: 22), + ), + const SizedBox(height: 12), + + getItemAddOn2( + 'Persona', + () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PersonaProfilePage(), + settings: const RouteSettings( + arguments: 'from_settings', + ), + ), + ); + }, + icon: SvgPicture.asset( + Assets.images.icPersonaProfile.path, + width: 24, + height: 24, + ), ), const SizedBox(height: 12), @@ -83,15 +101,19 @@ class _SettingsPageState extends State { ), ); }, - icon: Icons.bluetooth_connected_sharp, + icon: const Icon(Icons.bluetooth_connected_sharp, color: Colors.white, size: 22), ), const SizedBox(height: 12), // Advanced Settings - getItemAddOn2('Developer Mode', () async { - await routeToPage(context, const DeveloperSettingsPage()); - setState(() {}); - }, icon: Icons.code), + getItemAddOn2( + 'Developer Mode', + () async { + await routeToPage(context, const DeveloperSettingsPage()); + setState(() {}); + }, + icon: const Icon(Icons.code, color: Colors.white, size: 22), + ), const SizedBox(height: 12), // Help & Support @@ -100,7 +122,7 @@ class _SettingsPageState extends State { () async { await Intercom.instance.displayHelpCenter(); }, - icon: Icons.help_outline_outlined, + icon: const Icon(Icons.help_outline_outlined, color: Colors.white, size: 22), ), const SizedBox(height: 12), getItemAddOn2( @@ -108,7 +130,7 @@ class _SettingsPageState extends State { () async { await Intercom.instance.displayMessenger(); }, - icon: Icons.chat, + icon: const Icon(Icons.chat, color: Colors.white, size: 22), ), const SizedBox(height: 12), @@ -116,27 +138,31 @@ class _SettingsPageState extends State { getItemAddOn2( 'About Omi', () => routeToPage(context, const AboutOmiPage()), - icon: Icons.info_outline, + icon: const Icon(Icons.info_outline, color: Colors.white, size: 22), ), const SizedBox(height: 24), // Actions - getItemAddOn2('Sign Out', () async { - await showDialog( - context: context, - builder: (ctx) { - return getDialog(context, () { - Navigator.of(context).pop(); - }, () async { - await SharedPreferencesUtil().clearUserPreferences(); - Provider.of(context, listen: false).setRouting(PersonaProfileRouting.no_device); - await signOut(); - Navigator.of(context).pop(); - routeToPage(context, const DeciderWidget(), replace: true); - }, "Sign Out?", "Are you sure you want to sign out?"); - }, - ); - }, icon: Icons.logout), + getItemAddOn2( + 'Sign Out', + () async { + await showDialog( + context: context, + builder: (ctx) { + return getDialog(context, () { + Navigator.of(context).pop(); + }, () async { + await SharedPreferencesUtil().clearUserPreferences(); + Provider.of(context, listen: false).setRouting(PersonaProfileRouting.no_device); + await signOut(); + Navigator.of(context).pop(); + routeToPage(context, const DeciderWidget(), replace: true); + }, "Sign Out?", "Are you sure you want to sign out?"); + }, + ); + }, + icon: const Icon(Icons.logout, color: Colors.white, size: 22), + ), const SizedBox(height: 20), // Version Info @@ -166,7 +192,7 @@ class _SettingsPageState extends State { () async { await Intercom.instance.displayMessenger(); }, - icon: Icons.chat, + icon: const Icon(Icons.chat, color: Colors.white, size: 22), ), const SizedBox(height: 24), @@ -187,7 +213,7 @@ class _SettingsPageState extends State { }, "Sign Out?", "Are you sure you want to sign out?"); }, ); - }, icon: Icons.logout), + }, icon: const Icon(Icons.logout, color: Colors.white, size: 22)), const SizedBox(height: 20), // Version Info @@ -229,36 +255,6 @@ class _SettingsPageState extends State { Navigator.pop(context); }, ), - actions: [ - Consumer(builder: (context, personaProvider, _) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), - child: Container( - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.transparent, - ), - child: GestureDetector( - onTap: () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const PersonaProfilePage(), - settings: const RouteSettings( - arguments: 'from_settings', - ), - ), - ); - }, - child: SvgPicture.asset( - Assets.images.icPersonaProfile.path, - width: 28, - height: 28, - ), - ), - ), - ); - }), - ], elevation: 0, ), body: SingleChildScrollView( diff --git a/app/lib/pages/settings/widgets.dart b/app/lib/pages/settings/widgets.dart index a7495b04d..447fb7e52 100644 --- a/app/lib/pages/settings/widgets.dart +++ b/app/lib/pages/settings/widgets.dart @@ -47,15 +47,15 @@ getItemAddOn(String title, VoidCallback onTap, {required IconData icon, bool vis ); } -getItemAddOn2(String title, VoidCallback onTap, {required IconData icon}) { +getItemAddOn2(String title, VoidCallback onTap, {required Widget icon}) { return GestureDetector( onTap: () { MixpanelManager().pageOpened('Settings $title'); onTap(); }, - child: Container( - decoration: BoxDecoration( - color: const Color.fromARGB(255, 29, 29, 29), + child: Container( + decoration: BoxDecoration( + color: const Color.fromARGB(255, 29, 29, 29), borderRadius: BorderRadius.circular(10.0), boxShadow: [ BoxShadow( @@ -64,40 +64,32 @@ getItemAddOn2(String title, VoidCallback onTap, {required IconData icon}) { offset: const Offset(0, 2), ), ], - ), - child: Padding( + ), + child: Padding( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ Expanded( child: Row( children: [ - Icon( - icon, - color: Colors.white, - size: 22 - ), + icon, const SizedBox(width: 16), Expanded( child: Text( - title, + title, style: const TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w500, - ), + ), ), ), ], ), - ), - const Icon( - Icons.arrow_forward_ios, - color: Colors.white, - size: 16 ), - ], + const Icon(Icons.arrow_forward_ios, color: Colors.white, size: 16), + ], ), ), ), From 771c833d6beff12aad562fd1cb73529193651c2c Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 14:39:10 -0700 Subject: [PATCH 019/213] move the duration to right besdie the date --- .../conversations/widgets/conversation_list_item.dart | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/lib/pages/conversations/widgets/conversation_list_item.dart b/app/lib/pages/conversations/widgets/conversation_list_item.dart index 44e82f0b9..70ebe5375 100644 --- a/app/lib/pages/conversations/widgets/conversation_list_item.dart +++ b/app/lib/pages/conversations/widgets/conversation_list_item.dart @@ -230,18 +230,18 @@ class _ConversationListItemState extends State { alignment: Alignment.centerRight, child: ConversationNewStatusIndicator(text: "New 🚀"), ) - : Column( - crossAxisAlignment: CrossAxisAlignment.end, + : Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( dateTimeFormat('MMM d, h:mm a', widget.conversation.startedAt ?? widget.conversation.createdAt), style: TextStyle(color: Colors.grey.shade400, fontSize: 14), maxLines: 1, - textAlign: TextAlign.end, ), - if (widget.conversation.transcriptSegments.isNotEmpty) + if (widget.conversation.transcriptSegments.isNotEmpty && _getConversationDuration().isNotEmpty) Padding( - padding: const EdgeInsets.only(top: 2.0), + padding: const EdgeInsets.only(left: 8.0), child: Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( @@ -252,7 +252,6 @@ class _ConversationListItemState extends State { _getConversationDuration(), style: TextStyle(color: Colors.grey.shade300, fontSize: 11), maxLines: 1, - textAlign: TextAlign.end, ), ), ), From 8b5a212a3078c3b52e61df225dd741ae1c5438d4 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 14:50:57 -0700 Subject: [PATCH 020/213] lowerCamelCase for action_items --- app/lib/pages/conversation_detail/page.dart | 14 ++++---------- app/lib/widgets/conversation_bottom_bar.dart | 12 ++++++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/app/lib/pages/conversation_detail/page.dart b/app/lib/pages/conversation_detail/page.dart index 16936f2b2..c6a2e0578 100644 --- a/app/lib/pages/conversation_detail/page.dart +++ b/app/lib/pages/conversation_detail/page.dart @@ -10,7 +10,6 @@ import 'package:omi/pages/conversation_detail/widgets.dart'; import 'package:omi/pages/settings/people.dart'; import 'package:omi/providers/connectivity_provider.dart'; import 'package:omi/providers/conversation_provider.dart'; -import 'package:omi/utils/alerts/app_snackbar.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:omi/widgets/conversation_bottom_bar.dart'; @@ -60,7 +59,7 @@ class _ConversationDetailPageState extends State with Ti selectedTab = ConversationTab.summary; break; case 2: - selectedTab = ConversationTab.action_items; + selectedTab = ConversationTab.actionItems; break; default: debugPrint('Invalid tab index: ${_controller!.index}'); @@ -232,7 +231,7 @@ class _ConversationDetailPageState extends State with Ti case ConversationTab.summary: index = 1; break; - case ConversationTab.action_items: + case ConversationTab.actionItems: index = 2; break; default: @@ -594,18 +593,13 @@ class ActionItemsTab extends StatelessWidget { onTap: () => FocusScope.of(context).unfocus(), child: Consumer( builder: (context, provider, child) { - final hasActionItems = provider.conversation.structured.actionItems - .where((item) => !item.deleted) - .isNotEmpty; + final hasActionItems = provider.conversation.structured.actionItems.where((item) => !item.deleted).isNotEmpty; return ListView( shrinkWrap: true, children: [ const SizedBox(height: 24), - if (hasActionItems) - const ActionItemsListWidget() - else - _buildEmptyState(context), + if (hasActionItems) const ActionItemsListWidget() else _buildEmptyState(context), const SizedBox(height: 150) ], ); diff --git a/app/lib/widgets/conversation_bottom_bar.dart b/app/lib/widgets/conversation_bottom_bar.dart index 9b7ccead8..01b6f0a1d 100644 --- a/app/lib/widgets/conversation_bottom_bar.dart +++ b/app/lib/widgets/conversation_bottom_bar.dart @@ -13,7 +13,7 @@ enum ConversationBottomBarMode { detail // For viewing completed conversations } -enum ConversationTab { transcript, summary, action_items } +enum ConversationTab { transcript, summary, actionItems } class ConversationBottomBar extends StatelessWidget { final ConversationBottomBarMode mode; @@ -73,9 +73,9 @@ class ConversationBottomBar extends StatelessWidget { ...switch (mode) { ConversationBottomBarMode.recording => [_buildStopButton()], ConversationBottomBarMode.detail => [ - _buildSummaryTab(context), - _buildActionItemsTab(), - ], + _buildSummaryTab(context), + _buildActionItemsTab(), + ], _ => [_buildSummaryTab(context)], }, ], @@ -175,8 +175,8 @@ class ConversationBottomBar extends StatelessWidget { Widget _buildActionItemsTab() { return TabButton( icon: Icons.check_circle_outline, - isSelected: selectedTab == ConversationTab.action_items, - onTap: () => onTabSelected(ConversationTab.action_items), + isSelected: selectedTab == ConversationTab.actionItems, + onTap: () => onTabSelected(ConversationTab.actionItems), ); } } From 46cc4899d989356b41d3dc1efb25d958391d6345 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 15:48:37 -0700 Subject: [PATCH 021/213] improve changelog checking --- app/lib/pages/home/firmware_update.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/lib/pages/home/firmware_update.dart b/app/lib/pages/home/firmware_update.dart index 19807c5ac..2e311ab54 100644 --- a/app/lib/pages/home/firmware_update.dart +++ b/app/lib/pages/home/firmware_update.dart @@ -242,8 +242,8 @@ class _FirmwareUpdateState extends State with FirmwareMixin { } Widget _buildUpdateSection() { - bool hasChangelog = latestFirmwareDetails['changelog'] != null && - (List.from(latestFirmwareDetails['changelog'])).isNotEmpty; + dynamic changelogData = latestFirmwareDetails['changelog']; + bool hasChangelog = changelogData != null && changelogData is List && (List.from(changelogData)).isNotEmpty; return Card( color: Colors.black.withOpacity(0.2), @@ -340,7 +340,7 @@ class _FirmwareUpdateState extends State with FirmwareMixin { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - ...(List.from(latestFirmwareDetails['changelog'])).map((change) => Padding( + ...(List.from(changelogData)).map((change) => Padding( padding: const EdgeInsets.only(bottom: 6.0), child: Row( crossAxisAlignment: CrossAxisAlignment.start, From aa126f1c91dd6900813c73edbe3def99f2460d58 Mon Sep 17 00:00:00 2001 From: smian1 Date: Mon, 12 May 2025 17:23:26 -0700 Subject: [PATCH 022/213] Refine conversation transcript evaluation logic in should_discard_conversation function. Updated prompt to clarify criteria for keeping or discarding snippets, enhancing decision-making process. --- backend/utils/llm.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/backend/utils/llm.py b/backend/utils/llm.py index 35a621146..a677607b8 100644 --- a/backend/utils/llm.py +++ b/backend/utils/llm.py @@ -83,8 +83,26 @@ def should_discard_conversation(transcript: str) -> bool: parser = PydanticOutputParser(pydantic_object=DiscardConversation) prompt = ChatPromptTemplate.from_messages([ ''' - You will be given a conversation transcript, and your task is to determine if the conversation is worth storing as a memory or not. - It is not worth storing if there are no interesting topics, facts, or information, in that case, output discard = True. + You will receive a transcript snippet. Length is never a reason to discard. + + Task + Decide if the snippet should be saved as a memory. + + KEEP → output: discard = False + DISCARD → output: discard = True + + KEEP (discard = False) if it contains any of the following: + • a task, request, or action item + • a decision, commitment, or plan + • a question that requires follow-up + • personal facts, preferences, or details likely useful later + • an insight, summary, or key takeaway + + If none of these are present, DISCARD (discard = True). + + Return exactly one line: + discard = + Transcript: ```{transcript}``` From 3f4ff354adf15b7b6b3c6118106121cd462f7906 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 18:40:00 -0700 Subject: [PATCH 023/213] improve structured prompt for emoji --- backend/utils/llm.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/utils/llm.py b/backend/utils/llm.py index 35a621146..d34bca3a2 100644 --- a/backend/utils/llm.py +++ b/backend/utils/llm.py @@ -109,6 +109,7 @@ def get_transcript_structure(transcript: str, started_at: datetime, language_cod For the title, use the main topic of the conversation. For the overview, condense the conversation into a summary with the main topics discussed, make sure to capture the key points and important details from the conversation. + For the emoji, select a single emoji that vividly reflects the core subject, mood, or outcome of the conversation. Strive for an emoji that is specific and evocative, rather than generic (e.g., prefer 🎉 for a celebration over 👍 for general agreement, or 💡 for a new idea over 🧠 for general thought). For the action items, include a list of commitments, specific tasks or actionable steps from the conversation that the user is planning to do or has to do on that specific day or in future. Remember the speaker is busy so this has to be very efficient and concise, otherwise they might miss some critical tasks. Specify which speaker is responsible for each action item. For the category, classify the conversation into one of the available categories. For Calendar Events, include a list of events extracted from the conversation, that the user must have on his calendar. For date context, this conversation happened on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. @@ -142,6 +143,7 @@ def get_reprocess_transcript_structure(transcript: str, started_at: datetime, la For the title, use ```{title}```, if it is empty, use the main topic of the conversation. For the overview, condense the conversation into a summary with the main topics discussed, make sure to capture the key points and important details from the conversation. + For the emoji, select a single emoji that vividly reflects the core subject, mood, or outcome of the conversation. Strive for an emoji that is specific and evocative, rather than generic (e.g., prefer 🎉 for a celebration over 👍 for general agreement, or 💡 for a new idea over 🧠 for general thought). For the action items, include a list of commitments, specific tasks or actionable steps from the conversation that the user is planning to do or has to do on that specific day or in future. Remember the speaker is busy so this has to be very efficient and concise, otherwise they might miss some critical tasks. Specify which speaker is responsible for each action item. For the category, classify the conversation into one of the available categories. For Calendar Events, include a list of events extracted from the conversation, that the user must have on his calendar. For date context, this conversation happened on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. From 93c2bffe4ebe5cbf46c785bd0b50dcc2cd16c4f1 Mon Sep 17 00:00:00 2001 From: smian1 Date: Mon, 12 May 2025 20:46:20 -0700 Subject: [PATCH 024/213] Refactor Markdown styling in Plugins component for improved readability. Updated Tailwind classes to enhance text appearance and maintain consistency with design standards. --- web/frontend/src/components/memories/plugins/plugins.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/frontend/src/components/memories/plugins/plugins.tsx b/web/frontend/src/components/memories/plugins/plugins.tsx index 3c37259d3..347e9eddd 100644 --- a/web/frontend/src/components/memories/plugins/plugins.tsx +++ b/web/frontend/src/components/memories/plugins/plugins.tsx @@ -20,7 +20,7 @@ export default function Plugins({ plugins }: PluginsProps) {
- + {puglin.content}
From 2da9a681e01e064db5093b874f289bffbd3a8ace Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 22:13:26 -0700 Subject: [PATCH 025/213] frontend docker path fix --- web/frontend/Dockerfile | 2 +- web/frontend/Dockerfile.datadog | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/frontend/Dockerfile b/web/frontend/Dockerfile index 89767bcc5..651c45f6f 100644 --- a/web/frontend/Dockerfile +++ b/web/frontend/Dockerfile @@ -23,7 +23,7 @@ FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules #COPY frontend/. . -COPY frontend . +COPY . . ENV API_URL=https://backend-hhibjajaja-uc.a.run.app RUN npm run build diff --git a/web/frontend/Dockerfile.datadog b/web/frontend/Dockerfile.datadog index b6fd4cac1..5c4b34e90 100644 --- a/web/frontend/Dockerfile.datadog +++ b/web/frontend/Dockerfile.datadog @@ -24,7 +24,7 @@ WORKDIR /app COPY --from=deps /app/node_modules ./node_modules #COPY frontend/. . ENV API_URL=https://backend-hhibjajaja-uc.a.run.app -COPY frontend . +COPY . . RUN npm run build RUN echo "base files" From 7b0f5f6d908e2793876bfffc0ab2a1aa00790128 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Mon, 12 May 2025 22:24:08 -0700 Subject: [PATCH 026/213] fix paths in frontend dockerfile --- web/frontend/Dockerfile | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/web/frontend/Dockerfile b/web/frontend/Dockerfile index 651c45f6f..fcac86067 100644 --- a/web/frontend/Dockerfile +++ b/web/frontend/Dockerfile @@ -1,14 +1,14 @@ FROM node:18-alpine AS base +# Set working directory +WORKDIR /app + # Install dependencies only when needed FROM base AS deps RUN apk add --no-cache libc6-compat -WORKDIR /app +WORKDIR /app/web/frontend -RUN echo "deps: $(pwd)" -RUN ls -la - -# Install dependencies based on the preferred package manager +# Copy only the lock and package files COPY web/frontend/package.json web/frontend/yarn.lock* web/frontend/package-lock.json* web/frontend/pnpm-lock.yaml* ./ RUN \ @@ -20,39 +20,37 @@ RUN \ # Rebuild the source code only when needed FROM base AS builder -WORKDIR /app -COPY --from=deps /app/node_modules ./node_modules -#COPY frontend/. . -COPY . . +WORKDIR /app/web/frontend +COPY --from=deps /app/web/frontend/node_modules ./node_modules +COPY web/frontend . + ENV API_URL=https://backend-hhibjajaja-uc.a.run.app RUN npm run build -RUN echo "base files" +RUN echo "Files in builder:" RUN ls -la - -# Production image, copy all the files and run next +# Production image FROM base AS runner WORKDIR /app -RUN echo "production: $(pwd)" -RUN ls -la + ENV NODE_ENV production RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs -COPY --from=builder /app/public ./public +# Copy built output +COPY --from=builder /app/web/frontend/public ./public RUN mkdir .next RUN chown nextjs:nodejs .next -COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ -COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static +COPY --from=builder --chown=nextjs:nodejs /app/web/frontend/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/web/frontend/.next/static ./.next/static USER nextjs EXPOSE 3000 - ENV PORT 3000 ENV HOSTNAME "0.0.0.0" From 160dc96b0a277434779012255ce3c0bd6a6c8060 Mon Sep 17 00:00:00 2001 From: Thinh Date: Tue, 13 May 2025 18:35:52 +0700 Subject: [PATCH 027/213] STT wss safty on closing (#2366) --- backend/routers/transcribe.py | 52 +++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/backend/routers/transcribe.py b/backend/routers/transcribe.py index e7120e47a..fe7f85b9b 100644 --- a/backend/routers/transcribe.py +++ b/backend/routers/transcribe.py @@ -298,7 +298,6 @@ async def create_conversation_on_segment_received_task(finished_at: datetime): return # Process STT - _send_message_event(MessageServiceStatusEvent(status="stt_initiating", status_text="STT Service Starting")) soniox_socket = None soniox_socket2 = None speechmatics_socket = None @@ -381,8 +380,6 @@ async def deepgram_socket_send(data): await websocket.close(code=websocket_close_code) return - await _process_stt() - # Pusher # def create_pusher_task_handler(): @@ -495,9 +492,8 @@ async def close(code: int = 1000): transcript_consume = None audio_bytes_send = None audio_bytes_consume = None - pusher_connect, pusher_close, \ - transcript_send, transcript_consume, \ - audio_bytes_send, audio_bytes_consume = create_pusher_task_handler() + pusher_close = None + pusher_connect = None # Transcripts # @@ -733,26 +729,26 @@ async def receive_audio(dg_socket1, dg_socket2, soniox_socket, soniox_socket2, s websocket_close_code = 1011 finally: websocket_active = False - if dg_socket1: - dg_socket1.finish() - if dg_socket2: - dg_socket2.finish() - if soniox_socket: - await soniox_socket.close() - if soniox_socket2: - await soniox_socket2.close() - if speechmatics_socket: - await speechmatics_socket.close() # Start # try: + # Init STT + _send_message_event(MessageServiceStatusEvent(status="stt_initiating", status_text="STT Service Starting")) + await _process_stt() + + # Init pusher + pusher_connect, pusher_close, \ + transcript_send, transcript_consume, \ + audio_bytes_send, audio_bytes_consume = create_pusher_task_handler() + + # Tasks audio_process_task = asyncio.create_task( receive_audio(deepgram_socket, deepgram_socket2, soniox_socket, soniox_socket2, speechmatics_socket) ) stream_transcript_task = asyncio.create_task(stream_transcript_process()) - # Pusher + # Pusher tasks pusher_tasks = [asyncio.create_task(pusher_connect())] if transcript_consume is not None: pusher_tasks.append(asyncio.create_task(transcript_consume())) @@ -768,16 +764,36 @@ async def receive_audio(dg_socket1, dg_socket2, soniox_socket, soniox_socket2, s print(f"Error during WebSocket operation: {e}", uid) finally: websocket_active = False + + # STT sockets + try: + if deepgram_socket: + deepgram_socket.finish() + if deepgram_socket2: + deepgram_socket2.finish() + if soniox_socket: + await soniox_socket.close() + if soniox_socket2: + await soniox_socket2.close() + if speechmatics_socket: + await speechmatics_socket.close() + except Exception as e: + print(f"Error closing STT sockets: {e}", uid) + + # Client sockets if websocket.client_state == WebSocketState.CONNECTED: try: await websocket.close(code=websocket_close_code) except Exception as e: - print(f"Error closing WebSocket: {e}", uid) + print(f"Error closing Client WebSocket: {e}", uid) + + # Pusher sockets if pusher_close is not None: try: await pusher_close() except Exception as e: print(f"Error closing Pusher: {e}", uid) + print("_listen ended", uid) @router.websocket("/v3/listen") async def listen_handler_v3( From d23ad6ccbb45dcc8a5a850e51d00841d9f10368e Mon Sep 17 00:00:00 2001 From: Aarav Garg Date: Tue, 13 May 2025 15:37:56 -0700 Subject: [PATCH 028/213] fixed overflow error in conversation item header --- .../widgets/conversation_list_item.dart | 97 +++++++++---------- 1 file changed, 48 insertions(+), 49 deletions(-) diff --git a/app/lib/pages/conversations/widgets/conversation_list_item.dart b/app/lib/pages/conversations/widgets/conversation_list_item.dart index 70ebe5375..31f7bb4f1 100644 --- a/app/lib/pages/conversations/widgets/conversation_list_item.dart +++ b/app/lib/pages/conversations/widgets/conversation_list_item.dart @@ -84,8 +84,7 @@ class _ConversationListItemState extends State { } }, child: Padding( - padding: - EdgeInsets.only(top: 12, left: widget.isFromOnboarding ? 0 : 16, right: widget.isFromOnboarding ? 0 : 16), + padding: EdgeInsets.only(top: 12, left: widget.isFromOnboarding ? 0 : 16, right: widget.isFromOnboarding ? 0 : 16), child: Container( width: double.maxFinite, decoration: BoxDecoration( @@ -115,8 +114,7 @@ class _ConversationListItemState extends State { builder: (context, setState) { return ConfirmationDialog( title: "Delete Conversation?", - description: - "Are you sure you want to delete this conversation? This action cannot be undone.", + description: "Are you sure you want to delete this conversation? This action cannot be undone.", checkboxValue: !showDeleteConfirmation, checkboxText: "Don't ask me again", onCheckboxChanged: (value) { @@ -135,9 +133,7 @@ class _ConversationListItemState extends State { }); } else { return showDialog( - builder: (c) => getDialog(context, () => Navigator.pop(context), () => Navigator.pop(context), - 'Unable to Delete Conversation', 'Please check your internet connection and try again.', - singleButton: true, okButtonText: 'OK'), + builder: (c) => getDialog(context, () => Navigator.pop(context), () => Navigator.pop(context), 'Unable to Delete Conversation', 'Please check your internet connection and try again.', singleButton: true, okButtonText: 'OK'), context: context, ); } @@ -167,19 +163,13 @@ class _ConversationListItemState extends State { ? const SizedBox.shrink() : Text( structured.overview.decodeString, - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.grey.shade300, height: 1.3), + style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.grey.shade300, height: 1.3), maxLines: 2, ), widget.conversation.discarded ? Text( widget.conversation.getTranscript(maxCount: 100), - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.grey.shade300, height: 1.3), + style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.grey.shade300, height: 1.3), ) : const SizedBox(height: 8), ], @@ -197,45 +187,55 @@ class _ConversationListItemState extends State { return Padding( padding: const EdgeInsets.only(left: 4.0, right: 12), child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - widget.conversation.discarded - ? const SizedBox.shrink() - : Text(widget.conversation.structured.getEmoji(), - style: const TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.w500)), - widget.conversation.structured.category.isNotEmpty && !widget.conversation.discarded - ? const SizedBox(width: 12) - : const SizedBox.shrink(), - widget.conversation.structured.category.isNotEmpty - ? Container( - decoration: BoxDecoration( - color: widget.conversation.getTagColor(), - borderRadius: BorderRadius.circular(16), + // 🧠 Emoji + Tag + Flexible( + fit: FlexFit.tight, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (!widget.conversation.discarded) + Text( + widget.conversation.structured.getEmoji(), + style: const TextStyle(color: Colors.white, fontSize: 22, fontWeight: FontWeight.w500), ), - padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), - child: Text( - widget.conversation.getTag(), - style: - Theme.of(context).textTheme.bodyMedium!.copyWith(color: widget.conversation.getTagTextColor()), - maxLines: 1, + if (widget.conversation.structured.category.isNotEmpty && !widget.conversation.discarded) const SizedBox(width: 8), + if (widget.conversation.structured.category.isNotEmpty) + Flexible( + child: Container( + decoration: BoxDecoration( + color: widget.conversation.getTagColor(), + borderRadius: BorderRadius.circular(16), + ), + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + child: Text( + widget.conversation.getTag(), + style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: widget.conversation.getTagTextColor()), + overflow: TextOverflow.ellipsis, + maxLines: 1, + ), + ), ), - ) - : const SizedBox.shrink(), - const SizedBox( - width: 16, + ], + ), ), - Expanded( + + const SizedBox(width: 12), + + // 🕒 Timestamp + Duration or New + FittedBox( + fit: BoxFit.scaleDown, child: isNew - ? const Align( - alignment: Alignment.centerRight, - child: ConversationNewStatusIndicator(text: "New 🚀"), - ) + ? const ConversationNewStatusIndicator(text: "New 🚀") : Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, children: [ Text( - dateTimeFormat('MMM d, h:mm a', widget.conversation.startedAt ?? widget.conversation.createdAt), + dateTimeFormat( + 'MMM d, h:mm a', + widget.conversation.startedAt ?? widget.conversation.createdAt, + ), style: TextStyle(color: Colors.grey.shade400, fontSize: 14), maxLines: 1, ), @@ -257,7 +257,7 @@ class _ConversationListItemState extends State { ), ], ), - ) + ), ], ), ); @@ -283,8 +283,7 @@ class ConversationNewStatusIndicator extends StatefulWidget { State createState() => _ConversationNewStatusIndicatorState(); } -class _ConversationNewStatusIndicatorState extends State - with SingleTickerProviderStateMixin { +class _ConversationNewStatusIndicatorState extends State with SingleTickerProviderStateMixin { late AnimationController _controller; late Animation _opacityAnim; From b51278d31cd4b53e8847cb717b6168279af965be Mon Sep 17 00:00:00 2001 From: Aarav Garg Date: Tue, 13 May 2025 17:57:40 -0700 Subject: [PATCH 029/213] removed icons from bottom navigation bar --- app/lib/pages/home/page.dart | 57 ++++++++---------------------------- 1 file changed, 12 insertions(+), 45 deletions(-) diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index 6180def17..cd13cde90 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -206,8 +206,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker await Provider.of(context, listen: false).setUserPeople(); } if (mounted) { - await Provider.of(context, listen: false) - .streamDeviceRecording(device: Provider.of(context, listen: false).connectedDevice); + await Provider.of(context, listen: false).streamDeviceRecording(device: Provider.of(context, listen: false).connectedDevice); } // Navigate @@ -375,15 +374,12 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker ConversationsPage(), ChatPage(isPivotBottom: false), AppsPage(), - PersonaProfilePage(bottomMargin: 120), ], ), ), Consumer( builder: (context, home, child) { - if (home.chatFieldFocusNode.hasFocus || - home.convoSearchFieldFocusNode.hasFocus || - home.appsSearchFieldFocusNode.hasFocus) { + if (home.chatFieldFocusNode.hasFocus || home.convoSearchFieldFocusNode.hasFocus || home.appsSearchFieldFocusNode.hasFocus) { return const SizedBox.shrink(); } else { return Align( @@ -394,12 +390,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker color: Colors.black, borderRadius: BorderRadius.all(Radius.circular(18)), border: GradientBoxBorder( - gradient: LinearGradient(colors: [ - Color.fromARGB(127, 208, 208, 208), - Color.fromARGB(127, 188, 99, 121), - Color.fromARGB(127, 86, 101, 182), - Color.fromARGB(127, 126, 190, 236) - ]), + gradient: LinearGradient(colors: [Color.fromARGB(127, 208, 208, 208), Color.fromARGB(127, 188, 99, 121), Color.fromARGB(127, 86, 101, 182), Color.fromARGB(127, 126, 190, 236)]), width: 2, ), shape: BoxShape.rectangle, @@ -408,15 +399,13 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker labelPadding: const EdgeInsets.symmetric(vertical: 8), indicatorPadding: EdgeInsets.zero, onTap: (index) { - MixpanelManager() - .bottomNavigationTabClicked(['Memories', 'Chat', 'Explore'][index]); + MixpanelManager().bottomNavigationTabClicked(['Memories', 'Chat', 'Explore'][index]); primaryFocus?.unfocus(); if (home.selectedIndex == index) { return; } home.setIndex(index); - _controller?.animateToPage(index, - duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); + _controller?.animateToPage(index, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); }, indicatorColor: Colors.transparent, tabs: [ @@ -424,12 +413,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.home, - color: home.selectedIndex == 0 ? Colors.white : Colors.grey, - size: 22, - ), - const SizedBox(width: 8), Text( 'Home', style: TextStyle( @@ -445,12 +428,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.chat_bubble_outline, - color: home.selectedIndex == 1 ? Colors.white : Colors.grey, - size: 22, - ), - const SizedBox(width: 8), Text( 'Chat', style: TextStyle( @@ -466,12 +443,6 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( - Icons.explore_outlined, - color: home.selectedIndex == 2 ? Colors.white : Colors.grey, - size: 22, - ), - const SizedBox(width: 8), Text( 'Explore', style: TextStyle( @@ -541,14 +512,12 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return Center( child: Padding( padding: EdgeInsets.only(right: MediaQuery.sizeOf(context).width * 0.10), - child: const Text( - 'Explore', - style: TextStyle( - color: Colors.white, - fontSize: 22, - fontWeight: FontWeight.w600, - ) - ), + child: const Text('Explore', + style: TextStyle( + color: Colors.white, + fontSize: 22, + fontWeight: FontWeight.w600, + )), ), ); } else { @@ -589,9 +558,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker bool hasSpeech = SharedPreferencesUtil().hasSpeakerProfile; String transcriptModel = SharedPreferencesUtil().transcriptionModel; routeToPage(context, const SettingsPage()); - if (language != SharedPreferencesUtil().userPrimaryLanguage || - hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || - transcriptModel != SharedPreferencesUtil().transcriptionModel) { + if (language != SharedPreferencesUtil().userPrimaryLanguage || hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || transcriptModel != SharedPreferencesUtil().transcriptionModel) { if (context.mounted) { context.read().onRecordProfileSettingChanged(); } From 1cd23e096afbdc97b5f0a59ef977752fb044ff82 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Tue, 13 May 2025 21:51:32 -0700 Subject: [PATCH 030/213] track files usage in messages --- app/lib/pages/chat/page.dart | 8 ++++---- app/lib/utils/analytics/mixpanel.dart | 9 +++++++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/app/lib/pages/chat/page.dart b/app/lib/pages/chat/page.dart index 3b8a1b724..879ba0963 100644 --- a/app/lib/pages/chat/page.dart +++ b/app/lib/pages/chat/page.dart @@ -518,12 +518,12 @@ class ChatPageState extends State with AutomaticKeepAliveClientMixin { focusNode: home.chatFieldFocusNode, textAlign: TextAlign.start, textAlignVertical: TextAlignVertical.top, - decoration: InputDecoration( + decoration: const InputDecoration( hintText: 'Message', - hintStyle: const TextStyle(fontSize: 14.0, color: Colors.grey), + hintStyle: TextStyle(fontSize: 14.0, color: Colors.grey), focusedBorder: InputBorder.none, enabledBorder: InputBorder.none, - contentPadding: const EdgeInsets.only(top: 8, bottom: 10), + contentPadding: EdgeInsets.only(top: 8, bottom: 10), ), maxLines: null, keyboardType: TextInputType.multiline, @@ -600,7 +600,7 @@ class ChatPageState extends State with AutomaticKeepAliveClientMixin { _sendMessageUtil(String text) { var provider = context.read(); - MixpanelManager().chatMessageSent(text); + MixpanelManager().chatMessageSent(text, provider.uploadedFiles.isNotEmpty, provider.uploadedFiles.length); provider.setSendingMessage(true); provider.addMessageLocally(text); scrollToBottom(); diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index 9da892397..2f5be6f2c 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -208,8 +208,13 @@ class MixpanelManager { void conversationDeleted(ServerConversation conversation) => track('Memory Deleted', properties: getConversationEventProperties(conversation)); - void chatMessageSent(String message) => track('Chat Message Sent', - properties: {'message_length': message.length, 'message_word_count': message.split(' ').length}); + void chatMessageSent(String message, bool includesFiles, int numberOfFiles) => + track('Chat Message Sent', properties: { + 'message_length': message.length, + 'message_word_count': message.split(' ').length, + 'includes_files': includesFiles, + 'number_of_files': numberOfFiles, + }); void speechProfileCapturePageClicked() => track('Speech Profile Capture Page Clicked'); From e4a177a419fe0abccae697b4852fe3c2bf83cb52 Mon Sep 17 00:00:00 2001 From: Nik Shevchenko <43514161+kodjima33@users.noreply.github.com> Date: Tue, 13 May 2025 22:23:12 -0700 Subject: [PATCH 031/213] Update Introduction.mdx --- docs/docs/developer/apps/Introduction.mdx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/docs/developer/apps/Introduction.mdx b/docs/docs/developer/apps/Introduction.mdx index a115f738e..a01ce1dfa 100644 --- a/docs/docs/developer/apps/Introduction.mdx +++ b/docs/docs/developer/apps/Introduction.mdx @@ -30,6 +30,8 @@ In omi App: Start speaking, you'll see Real-time transcript on [webhook.site ](https://webhook.site) +If you don't see "explore", select "connect device" in onboarding or in settings + ## What Are OMI Apps? OMI apps are modular extensions that augment the core functionality of the app. They can modify app's From d070d4be621286721987f98afe089e2d469f78b6 Mon Sep 17 00:00:00 2001 From: Thinh Date: Wed, 14 May 2025 13:18:33 +0700 Subject: [PATCH 032/213] Deactivate the backend-listen streams after 30s without audio bytes; yielding 1s when processing the old conversation for socket acceptance (#2370) --- backend/routers/transcribe.py | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/backend/routers/transcribe.py b/backend/routers/transcribe.py index fe7f85b9b..a66d49f11 100644 --- a/backend/routers/transcribe.py +++ b/backend/routers/transcribe.py @@ -97,6 +97,8 @@ def _send_message_event(msg: MessageEvent): started_at = time.time() timeout_seconds = 420 # 7m # Soft timeout, should < MODAL_TIME_OUT - 3m has_timeout = os.getenv('NO_SOCKET_TIMEOUT') is None + inactivity_timeout_seconds = 30 + last_audio_received_time = None # Send pong every 10s then handle it in the app \ # since Starlette is not support pong automatically @@ -105,6 +107,7 @@ async def send_heartbeat(): nonlocal websocket_active nonlocal websocket_close_code nonlocal started_at + nonlocal last_audio_received_time try: while websocket_active: @@ -121,6 +124,13 @@ async def send_heartbeat(): websocket_active = False break + # Inactivity timeout + if last_audio_received_time and time.time() - last_audio_received_time > inactivity_timeout_seconds: + print(f"Session timeout due to inactivity ({inactivity_timeout_seconds}s)", uid) + websocket_close_code = 1001 + websocket_active = False + break + # next await asyncio.sleep(10) except WebSocketDisconnect: @@ -180,16 +190,21 @@ async def _create_conversation(conversation: dict): _send_message_event(ConversationEvent(event_type="memory_created", memory=conversation, messages=messages)) - async def finalize_processing_conversations(processing: List[dict]): + async def finalize_processing_conversations(): # handle edge case of conversation was actually processing? maybe later, doesn't hurt really anyway. # also fix from getMemories endpoint? + processing = conversations_db.get_processing_conversations(uid) print('finalize_processing_conversations len(processing):', len(processing), uid) + if not processing or len(processing) == 0: + return + + # sleep for 1 second to yeld the network for ws accepted. + await asyncio.sleep(1) for conversation in processing: await _create_conversation(conversation) # Process processing conversations - processing = conversations_db.get_processing_conversations(uid) - asyncio.create_task(finalize_processing_conversations(processing)) + asyncio.create_task(finalize_processing_conversations()) # Send last completed conversation to client async def send_last_conversation(): @@ -674,11 +689,14 @@ async def stream_transcript_process(): async def receive_audio(dg_socket1, dg_socket2, soniox_socket, soniox_socket2, speechmatics_socket1): nonlocal websocket_active nonlocal websocket_close_code + nonlocal last_audio_received_time timer_start = time.time() + last_audio_received_time = timer_start try: while websocket_active: data = await websocket.receive_bytes() + last_audio_received_time = time.time() if codec == 'opus' and sample_rate == 16000: data = decoder.decode(bytes(data), frame_size=frame_size) # audio_data.extend(data) From 489a40bdecac947de245ecd01ad19923d0891cfc Mon Sep 17 00:00:00 2001 From: Aarav Garg Date: Wed, 14 May 2025 00:28:01 -0700 Subject: [PATCH 033/213] memories added to main bottom navbar; icons changed to font awesome on bottom navbar --- app/.vscode/settings.json | 20 ++ app/lib/pages/home/page.dart | 132 +++++--- app/lib/pages/memories/page.dart | 282 ++++++------------ .../pages/memories/widgets/category_chip.dart | 14 +- app/lib/pages/settings/about.dart | 2 +- app/lib/pages/settings/profile.dart | 12 +- app/macos/Runner/GoogleService-Info.plist | 36 +++ app/pubspec.yaml | 1 + backend/.python-version | 1 + 9 files changed, 253 insertions(+), 247 deletions(-) create mode 100644 app/.vscode/settings.json create mode 100644 app/macos/Runner/GoogleService-Info.plist create mode 100644 backend/.python-version diff --git a/app/.vscode/settings.json b/app/.vscode/settings.json new file mode 100644 index 000000000..97fb71fdc --- /dev/null +++ b/app/.vscode/settings.json @@ -0,0 +1,20 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Flutter Dev", + "request": "launch", + "type": "dart", + "flutterMode": "debug", + "args": ["--flavor", "dev"] + }, + { + "name": "Flutter Prod", + "request": "launch", + "type": "dart", + "flutterMode": "release", + "args": ["--flavor", "prod"] + } + ], + "java.configuration.updateBuildConfiguration": "interactive" + } \ No newline at end of file diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index cd13cde90..c2ffe4223 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:omi/gen/assets.gen.dart'; import 'package:omi/pages/persona/persona_provider.dart'; import 'package:omi/backend/http/api/users.dart'; @@ -185,6 +186,9 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker case "apps": homePageIdx = 2; break; + case "memoriesPage": + homePageIdx = 3; + break; } } @@ -354,9 +358,9 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker builder: (context, homeProvider, _) { return Scaffold( backgroundColor: Theme.of(context).colorScheme.primary, - appBar: homeProvider.selectedIndex == 3 ? null : _buildAppBar(context), + appBar: homeProvider.selectedIndex == 4 ? null : _buildAppBar(context), body: DefaultTabController( - length: 3, + length: 4, initialIndex: _controller?.initialPage ?? 0, child: GestureDetector( onTap: () { @@ -374,6 +378,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker ConversationsPage(), ChatPage(isPivotBottom: false), AppsPage(), + MemoriesPage(), ], ), ), @@ -385,6 +390,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return Align( alignment: Alignment.bottomCenter, child: Container( + padding: const EdgeInsets.symmetric(horizontal: 10), margin: const EdgeInsets.fromLTRB(20, 16, 20, 42), decoration: const BoxDecoration( color: Colors.black, @@ -396,10 +402,10 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker shape: BoxShape.rectangle, ), child: TabBar( - labelPadding: const EdgeInsets.symmetric(vertical: 8), + labelPadding: const EdgeInsets.symmetric(vertical: 10), indicatorPadding: EdgeInsets.zero, onTap: (index) { - MixpanelManager().bottomNavigationTabClicked(['Memories', 'Chat', 'Explore'][index]); + MixpanelManager().bottomNavigationTabClicked(['Memories', 'Chat', 'Explore', 'Memories'][index]); primaryFocus?.unfocus(); if (home.selectedIndex == index) { return; @@ -410,45 +416,80 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker indicatorColor: Colors.transparent, tabs: [ Tab( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ + Icon( + FontAwesomeIcons.house, + color: home.selectedIndex == 0 ? Colors.white : Colors.grey, + size: 18, + ), + const SizedBox(height: 6), Text( 'Home', style: TextStyle( color: home.selectedIndex == 0 ? Colors.white : Colors.grey, - fontSize: MediaQuery.sizeOf(context).width < 410 ? 14 : 16, - fontWeight: home.selectedIndex == 0 ? FontWeight.w600 : FontWeight.normal, + fontSize: 12, ), ), ], ), ), Tab( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ + Icon( + FontAwesomeIcons.solidMessage, + color: home.selectedIndex == 1 ? Colors.white : Colors.grey, + size: 18, + ), + const SizedBox(height: 6), Text( 'Chat', style: TextStyle( color: home.selectedIndex == 1 ? Colors.white : Colors.grey, - fontSize: MediaQuery.sizeOf(context).width < 410 ? 14 : 16, - fontWeight: home.selectedIndex == 1 ? FontWeight.w600 : FontWeight.normal, + fontSize: 12, ), ), ], ), ), Tab( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, + child: Column( + mainAxisSize: MainAxisSize.min, children: [ + Icon( + FontAwesomeIcons.search, + color: home.selectedIndex == 2 ? Colors.white : Colors.grey, + size: 18, + ), + const SizedBox(height: 6), Text( 'Explore', style: TextStyle( color: home.selectedIndex == 2 ? Colors.white : Colors.grey, - fontSize: MediaQuery.sizeOf(context).width < 410 ? 14 : 16, - fontWeight: home.selectedIndex == 2 ? FontWeight.w600 : FontWeight.normal, + fontSize: 12, + ), + ), + ], + ), + ), + Tab( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + FontAwesomeIcons.brain, + color: home.selectedIndex == 3 ? Colors.white : Colors.grey, + size: 18, + ), + const SizedBox(height: 6), + Text( + 'Memories', + style: TextStyle( + color: home.selectedIndex == 3 ? Colors.white : Colors.grey, + fontSize: 12, ), ), ], @@ -520,6 +561,18 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker )), ), ); + } else if (provider.selectedIndex == 3) { + return Center( + child: Padding( + padding: EdgeInsets.only(right: MediaQuery.sizeOf(context).width * 0.10), + child: const Text('Memories', + style: TextStyle( + color: Colors.white, + fontSize: 22, + fontWeight: FontWeight.w600, + )), + ), + ); } else { return Expanded( child: Center( @@ -538,33 +591,30 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker ), Row( children: [ - Padding( - padding: const EdgeInsets.only(right: 8.0), - child: Container( - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: Colors.transparent, + Container( + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.transparent, + ), + child: IconButton( + padding: const EdgeInsets.fromLTRB(2.0, 2.0, 0, 2.0), + icon: SvgPicture.asset( + Assets.images.icSettingPersona.path, + width: 36, + height: 36, ), - child: IconButton( - padding: const EdgeInsets.all(8.0), - icon: SvgPicture.asset( - Assets.images.icSettingPersona.path, - width: 36, - height: 36, - ), - onPressed: () { - MixpanelManager().pageOpened('Settings'); - String language = SharedPreferencesUtil().userPrimaryLanguage; - bool hasSpeech = SharedPreferencesUtil().hasSpeakerProfile; - String transcriptModel = SharedPreferencesUtil().transcriptionModel; - routeToPage(context, const SettingsPage()); - if (language != SharedPreferencesUtil().userPrimaryLanguage || hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || transcriptModel != SharedPreferencesUtil().transcriptionModel) { - if (context.mounted) { - context.read().onRecordProfileSettingChanged(); - } + onPressed: () { + MixpanelManager().pageOpened('Settings'); + String language = SharedPreferencesUtil().userPrimaryLanguage; + bool hasSpeech = SharedPreferencesUtil().hasSpeakerProfile; + String transcriptModel = SharedPreferencesUtil().transcriptionModel; + routeToPage(context, const SettingsPage()); + if (language != SharedPreferencesUtil().userPrimaryLanguage || hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || transcriptModel != SharedPreferencesUtil().transcriptionModel) { + if (context.mounted) { + context.read().onRecordProfileSettingChanged(); } - }, - ), + } + }, ), ), ], diff --git a/app/lib/pages/memories/page.dart b/app/lib/pages/memories/page.dart index e2fbf6e4c..e957aa919 100644 --- a/app/lib/pages/memories/page.dart +++ b/app/lib/pages/memories/page.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:omi/backend/schema/memory.dart'; import 'package:omi/providers/memories_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; @@ -62,55 +63,6 @@ class MemoriesPageState extends State { return counts; } - Widget _buildSearchBar() { - return Consumer( - builder: (context, provider, _) { - return Padding( - padding: const EdgeInsets.fromLTRB(16, 4, 16, 4), - child: SearchBar( - hintText: 'Search memories', - leading: const Icon(Icons.search, color: Colors.white70, size: 18), - backgroundColor: WidgetStateProperty.all(AppStyles.backgroundSecondary), - elevation: WidgetStateProperty.all(0), - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric(horizontal: 12, vertical: 8), - ), - controller: _searchController, - trailing: provider.searchQuery.isNotEmpty - ? [ - IconButton( - icon: const Icon(Icons.close, color: Colors.white70, size: 16), - padding: EdgeInsets.zero, - constraints: const BoxConstraints( - minHeight: 36, - minWidth: 36, - ), - onPressed: () { - _searchController.clear(); - setState(() {}); - provider.setSearchQuery(''); - }, - ) - ] - : null, - hintStyle: WidgetStateProperty.all( - TextStyle(color: AppStyles.textTertiary, fontSize: 14), - ), - textStyle: WidgetStateProperty.all( - TextStyle(color: AppStyles.textPrimary, fontSize: 14), - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(AppStyles.radiusMedium), - ), - ), - onChanged: (value) => provider.setSearchQuery(value), - ), - ); - } - ); - } - @override Widget build(BuildContext context) { return Consumer( @@ -131,153 +83,117 @@ class MemoriesPageState extends State { controller: _scrollController, headerSliverBuilder: (context, innerBoxIsScrolled) { return [ - // AppBar with the title and action buttons - SliverAppBar( - backgroundColor: Theme.of(context).colorScheme.primary, - pinned: true, - centerTitle: true, - title: const Text('Memories', style: AppStyles.title), - leading: null, - automaticallyImplyLeading: true, - titleSpacing: 0, - actions: [ - IconButton( - icon: Stack( - alignment: Alignment.center, - children: [ - Icon( - Icons.reviews_outlined, - color: unreviewedCount > 0 ? Colors.white : Colors.grey.shade600, - size: 22, - ), - if (unreviewedCount > 0) - Positioned( - top: 0, - right: 0, - child: Container( - padding: const EdgeInsets.all(2), - decoration: BoxDecoration( - color: Colors.red, - borderRadius: BorderRadius.circular(8), - ), - constraints: const BoxConstraints( - minWidth: 16, - minHeight: 16, - ), - child: Text( - '$unreviewedCount', - style: const TextStyle( - color: Colors.white, - fontSize: 10, - fontWeight: FontWeight.bold, - ), - textAlign: TextAlign.center, + // Top row with search bar and action buttons + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.fromLTRB(16, 12, 16, 10), + child: Row( + children: [ + // Search bar taking most of the space + Expanded( + child: SizedBox( + height: 44, // Match button height + child: SearchBar( + hintText: 'Search memories', + leading: const Padding( + padding: EdgeInsets.only(left: 6.0), + child: Icon(FontAwesomeIcons.magnifyingGlass, color: Colors.white70, size: 14), + ), + backgroundColor: WidgetStateProperty.all(AppStyles.backgroundSecondary), + elevation: WidgetStateProperty.all(0), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(horizontal: 12, vertical: 4), // Reduce vertical padding + ), + controller: _searchController, + trailing: provider.searchQuery.isNotEmpty + ? [ + IconButton( + icon: const Icon(Icons.close, color: Colors.white70, size: 16), + padding: EdgeInsets.zero, + constraints: const BoxConstraints( + minHeight: 36, + minWidth: 36, + ), + onPressed: () { + _searchController.clear(); + setState(() {}); + provider.setSearchQuery(''); + }, + ) + ] + : null, + hintStyle: WidgetStateProperty.all( + TextStyle(color: AppStyles.textTertiary, fontSize: 14), + ), + textStyle: WidgetStateProperty.all( + TextStyle(color: AppStyles.textPrimary, fontSize: 14), + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppStyles.radiusLarge), ), ), + onChanged: (value) => provider.setSearchQuery(value), ), - ], - ), - onPressed: unreviewedCount > 0 - ? () { - _showReviewSheet(provider.unreviewed); - MixpanelManager().memoriesPageReviewBtn(); - } - : null, - tooltip: unreviewedCount > 0 ? 'Review memories' : 'No memories to review', - ), - IconButton( - icon: const Icon(Icons.settings), - onPressed: () { - _showMemoryManagementSheet(context, provider); - }, - tooltip: 'Manage memories', - ), - IconButton( - icon: const Icon(Icons.add), - onPressed: () { - showMemoryDialog(context, provider); - MixpanelManager().memoriesPageCreateMemoryBtn(); - }, - ), - ], - ), + ), + ), - // Category filter - if (categoryCounts.isNotEmpty) - SliverToBoxAdapter( - child: Container( - height: 50, - margin: const EdgeInsets.fromLTRB(0, 0, 0, 8), - child: ListView( - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(horizontal: 16), - children: [ - Padding( - padding: const EdgeInsets.only(right: 8), - child: FilterChip( - label: Text( - 'All (${provider.memories.length})', - style: TextStyle( - color: _selectedCategory == null ? Colors.black : Colors.white70, - fontWeight: _selectedCategory == null ? FontWeight.w600 : FontWeight.normal, - fontSize: 13, - ), + const SizedBox(width: 8), + // Settings button + SizedBox( + width: 44, + height: 44, + child: ElevatedButton( + onPressed: () { + _showMemoryManagementSheet(context, provider); + }, + style: ElevatedButton.styleFrom( + backgroundColor: AppStyles.backgroundSecondary, + foregroundColor: Colors.white, + padding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), - selected: _selectedCategory == null, - onSelected: (_) => _filterByCategory(null), - backgroundColor: AppStyles.backgroundTertiary, - selectedColor: Colors.white, - checkmarkColor: Colors.black, - showCheckmark: false, - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), ), + child: Icon(FontAwesomeIcons.gear, size: 16), ), - ...categoryCounts.entries.map((entry) { - final category = entry.key; - final count = entry.value; - - // Format category name to be more concise - String categoryName = category.toString().split('.').last; - // Capitalize first letter only - categoryName = categoryName[0].toUpperCase() + categoryName.substring(1); - - return Padding( - padding: const EdgeInsets.only(right: 8), - child: FilterChip( - label: Text( - '$categoryName ($count)', - style: TextStyle( - color: _selectedCategory == category ? Colors.black : Colors.white70, - fontWeight: _selectedCategory == category ? FontWeight.w600 : FontWeight.normal, - fontSize: 13, - ), - ), - selected: _selectedCategory == category, - onSelected: (_) => _filterByCategory(category), - backgroundColor: AppStyles.backgroundTertiary, - selectedColor: Colors.white, - checkmarkColor: Colors.black, - showCheckmark: false, - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), + ), + const SizedBox(width: 8), + // Create button + SizedBox( + width: 44, + height: 44, + child: ElevatedButton( + onPressed: () { + showMemoryDialog(context, provider); + MixpanelManager().memoriesPageCreateMemoryBtn(); + }, + style: ElevatedButton.styleFrom( + backgroundColor: AppStyles.backgroundSecondary, + foregroundColor: Colors.white, + padding: EdgeInsets.zero, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), ), - ); - }), - ], - ), + ), + child: Icon(FontAwesomeIcons.plus, size: 18), + ), + ), + ], ), ), + ), - // Search bar that appears when scrolling + // Remove category filter section + + // Empty persistent header with zero height SliverPersistentHeader( pinned: true, floating: true, delegate: _SliverSearchBarDelegate( minHeight: 0, - maxHeight: 60, - child: Container( - color: Theme.of(context).colorScheme.primary, - child: _buildSearchBar(), - ), + maxHeight: 0, + child: Container(), ), ), ]; @@ -311,7 +227,7 @@ class MemoriesPageState extends State { ), ) : ListView.builder( - padding: const EdgeInsets.all(16), + padding: const EdgeInsets.only(top: 8, left: 16, right: 16, bottom: 16), // Reduce top padding itemCount: provider.filteredMemories.length, itemBuilder: (context, index) { final memory = provider.filteredMemories[index]; @@ -446,8 +362,6 @@ class _SliverSearchBarDelegate extends SliverPersistentHeaderDelegate { @override bool shouldRebuild(_SliverSearchBarDelegate oldDelegate) { - return maxHeight != oldDelegate.maxHeight || - minHeight != oldDelegate.minHeight || - child != oldDelegate.child; + return maxHeight != oldDelegate.maxHeight || minHeight != oldDelegate.minHeight || child != oldDelegate.child; } } diff --git a/app/lib/pages/memories/widgets/category_chip.dart b/app/lib/pages/memories/widgets/category_chip.dart index 409db1fd9..ec00ce756 100644 --- a/app/lib/pages/memories/widgets/category_chip.dart +++ b/app/lib/pages/memories/widgets/category_chip.dart @@ -78,7 +78,7 @@ class CategoryChip extends StatelessWidget { displayName = "Life"; break; case MemoryCategory.interests: - displayName = "Int"; + displayName = "Interest"; break; case MemoryCategory.work: displayName = "Work"; @@ -109,13 +109,9 @@ class CategoryChip extends StatelessWidget { height: 26, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 0), decoration: BoxDecoration( - color: isSelected - ? (onTap != null ? categoryColor : categoryColor.withOpacity(0.15)) - : Colors.grey.shade800.withOpacity(0.6), + color: isSelected ? (onTap != null ? categoryColor : categoryColor.withOpacity(0.15)) : Colors.grey.shade800.withOpacity(0.6), borderRadius: BorderRadius.circular(13), - border: isSelected && onTap == null - ? Border.all(color: categoryColor, width: 1) - : null, + border: isSelected && onTap == null ? Border.all(color: categoryColor, width: 1) : null, ), child: Row( mainAxisSize: MainAxisSize.min, @@ -135,9 +131,7 @@ class CategoryChip extends StatelessWidget { Text( displayName + countText, style: TextStyle( - color: isSelected - ? (onTap != null ? Colors.white : categoryColor) - : Colors.white70, + color: isSelected ? (onTap != null ? Colors.white : categoryColor) : Colors.white70, fontSize: 12, fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), diff --git a/app/lib/pages/settings/about.dart b/app/lib/pages/settings/about.dart index a1bc7ba4b..53b6a4d16 100644 --- a/app/lib/pages/settings/about.dart +++ b/app/lib/pages/settings/about.dart @@ -60,7 +60,7 @@ class _AboutOmiPageState extends State { ListTile( contentPadding: const EdgeInsets.fromLTRB(4, 0, 24, 0), title: const Text('Join the community!', style: TextStyle(color: Colors.white)), - subtitle: const Text('4900+ members and counting.'), + subtitle: const Text('7000+ members and counting.'), trailing: const Icon(Icons.discord, color: Colors.purple, size: 20), onTap: () { MixpanelManager().pageOpened('About Join Discord'); diff --git a/app/lib/pages/settings/profile.dart b/app/lib/pages/settings/profile.dart index 1ff31daad..2f31a83bd 100644 --- a/app/lib/pages/settings/profile.dart +++ b/app/lib/pages/settings/profile.dart @@ -222,15 +222,6 @@ class _ProfilePageState extends State { routeToPage(context, const UserPeoplePage()); }, ), - _buildProfileTile( - title: 'Memories', - subtitle: 'What Omi has learned about you 👀', - icon: Icons.self_improvement, - onTap: () { - routeToPage(context, const MemoriesPage()); - MixpanelManager().pageOpened('Profile Facts'); - }, - ), // PAYMENT SECTION _buildSectionHeader('PAYMENT'), @@ -268,8 +259,7 @@ class _ProfilePageState extends State { icon: Icons.copy_rounded, onTap: () { Clipboard.setData(ClipboardData(text: SharedPreferencesUtil().uid)); - ScaffoldMessenger.of(context) - .showSnackBar(const SnackBar(content: Text('User ID copied to clipboard'))); + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('User ID copied to clipboard'))); }, ), _buildProfileTile( diff --git a/app/macos/Runner/GoogleService-Info.plist b/app/macos/Runner/GoogleService-Info.plist new file mode 100644 index 000000000..df363763f --- /dev/null +++ b/app/macos/Runner/GoogleService-Info.plist @@ -0,0 +1,36 @@ + + + + + CLIENT_ID + 1031333818730-a81299nnu9r6bn2hdu6hnh9l71k20n6m.apps.googleusercontent.com + REVERSED_CLIENT_ID + com.googleusercontent.apps.1031333818730-a81299nnu9r6bn2hdu6hnh9l71k20n6m + ANDROID_CLIENT_ID + 1031333818730-1cgqp3jc5p8n2rk467pl4t56qc4lnnbr.apps.googleusercontent.com + API_KEY + AIzaSyBPlXLWWpBIlJQ3WTi82tMOaLSdHsSwU7k + GCM_SENDER_ID + 1031333818730 + PLIST_VERSION + 1 + BUNDLE_ID + com.friend.ios + PROJECT_ID + based-hardware-dev + STORAGE_BUCKET + based-hardware-dev.firebasestorage.app + IS_ADS_ENABLED + + IS_ANALYTICS_ENABLED + + IS_APPINVITE_ENABLED + + IS_GCM_ENABLED + + IS_SIGNIN_ENABLED + + GOOGLE_APP_ID + 1:1031333818730:ios:7475273b3f7ee0fdafb513 + + \ No newline at end of file diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 2306f9842..98bcbf023 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -104,6 +104,7 @@ dependencies: flutter_svg: ^2.0.16 file_picker: 8.0.7 photo_view: ^0.15.0 + font_awesome_flutter: ^10.8.0 dependency_overrides: http: ^1.2.1 diff --git a/backend/.python-version b/backend/.python-version new file mode 100644 index 000000000..9919bf8c9 --- /dev/null +++ b/backend/.python-version @@ -0,0 +1 @@ +3.10.13 From 9d62090997bbb60e6a0a7b78515da20399440dba Mon Sep 17 00:00:00 2001 From: Aarav Garg Date: Wed, 14 May 2025 00:29:58 -0700 Subject: [PATCH 034/213] memories added to main bottom navbar; icons changed to font awesome on bottom navbar --- app/.vscode/settings.json | 20 ------------- app/macos/Runner/GoogleService-Info.plist | 36 ----------------------- backend/.python-version | 1 - 3 files changed, 57 deletions(-) delete mode 100644 app/.vscode/settings.json delete mode 100644 app/macos/Runner/GoogleService-Info.plist delete mode 100644 backend/.python-version diff --git a/app/.vscode/settings.json b/app/.vscode/settings.json deleted file mode 100644 index 97fb71fdc..000000000 --- a/app/.vscode/settings.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Flutter Dev", - "request": "launch", - "type": "dart", - "flutterMode": "debug", - "args": ["--flavor", "dev"] - }, - { - "name": "Flutter Prod", - "request": "launch", - "type": "dart", - "flutterMode": "release", - "args": ["--flavor", "prod"] - } - ], - "java.configuration.updateBuildConfiguration": "interactive" - } \ No newline at end of file diff --git a/app/macos/Runner/GoogleService-Info.plist b/app/macos/Runner/GoogleService-Info.plist deleted file mode 100644 index df363763f..000000000 --- a/app/macos/Runner/GoogleService-Info.plist +++ /dev/null @@ -1,36 +0,0 @@ - - - - - CLIENT_ID - 1031333818730-a81299nnu9r6bn2hdu6hnh9l71k20n6m.apps.googleusercontent.com - REVERSED_CLIENT_ID - com.googleusercontent.apps.1031333818730-a81299nnu9r6bn2hdu6hnh9l71k20n6m - ANDROID_CLIENT_ID - 1031333818730-1cgqp3jc5p8n2rk467pl4t56qc4lnnbr.apps.googleusercontent.com - API_KEY - AIzaSyBPlXLWWpBIlJQ3WTi82tMOaLSdHsSwU7k - GCM_SENDER_ID - 1031333818730 - PLIST_VERSION - 1 - BUNDLE_ID - com.friend.ios - PROJECT_ID - based-hardware-dev - STORAGE_BUCKET - based-hardware-dev.firebasestorage.app - IS_ADS_ENABLED - - IS_ANALYTICS_ENABLED - - IS_APPINVITE_ENABLED - - IS_GCM_ENABLED - - IS_SIGNIN_ENABLED - - GOOGLE_APP_ID - 1:1031333818730:ios:7475273b3f7ee0fdafb513 - - \ No newline at end of file diff --git a/backend/.python-version b/backend/.python-version deleted file mode 100644 index 9919bf8c9..000000000 --- a/backend/.python-version +++ /dev/null @@ -1 +0,0 @@ -3.10.13 From 7f01863dace4eecd35aa2d2fc30400648f53e488 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 09:01:38 -0700 Subject: [PATCH 035/213] emove .vscode from repo and ignore it going forward --- .gitignore | 5 +--- .vscode/launch.json | 72 --------------------------------------------- 2 files changed, 1 insertion(+), 76 deletions(-) delete mode 100644 .vscode/launch.json diff --git a/.gitignore b/.gitignore index a9a7798aa..d9a4b9d6c 100644 --- a/.gitignore +++ b/.gitignore @@ -25,10 +25,7 @@ build/ dist/ .build/ .swiftpm/ -# VS Code - exclude everything except specific files -.vscode/* -!.vscode/launch.json -!.vscode/extensions.json +.vscode/ # Android specific **/android/**/build/ diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 7f40c923e..000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "name": "Uvicorn (backend)", - "type": "python", - "request": "launch", - "module": "uvicorn", - "cwd": "${workspaceFolder}/backend", - "args": [ - "main:app", - "--reload", - "--env-file", ".dev.env", - // "--host", "0.0.0.0", - "--port", "8000", - // "--log-level", "debug", - // "--log-config", "logging_config.json" - ], - "jinja": true, - "python": "${workspaceFolder}/backend/venv/bin/python", - "justMyCode": false, - "env": { - "PYTHONPATH": "${workspaceFolder}/backend", - "LD_LIBRARY_PATH": "/usr/local/lib:/opt/homebrew/lib:${env:LD_LIBRARY_PATH}", - "DYLD_LIBRARY_PATH": "/opt/homebrew/lib:${env:DYLD_LIBRARY_PATH}", - "LIBRARY_PATH": "/opt/homebrew/lib:${env:LIBRARY_PATH}", - "PKG_CONFIG_PATH": "/opt/homebrew/lib/pkgconfig:${env:PKG_CONFIG_PATH}" - } - }, - { - "name": "Flutter (dev)", - "type": "dart", - "request": "launch", - "program": "${workspaceFolder}/app/lib/main.dart", - "cwd": "${workspaceFolder}/app", - "flutterMode": "debug", - "args": [ - "--flavor", - "dev" - ] - }, - { - "name": "Flutter (dev) - iOS Specific Device", - "type": "dart", - "request": "launch", - "program": "${workspaceFolder}/app/lib/main.dart", - "cwd": "${workspaceFolder}/app", - "flutterMode": "debug", - "args": [ - "--flavor", - "dev", - "-d", - "00008130-000C5196386B8D3A" - ] - }, - { - "name": "Flutter Run (Terminal)", - "type": "node", - "request": "launch", - "runtimeExecutable": "flutter", - "cwd": "${workspaceFolder}/app", - "args": [ - "run", - "--flavor", - "dev", - "-d", - "00008130-000C5196386B8D3A" - ], - "console": "integratedTerminal" - } - ] -} \ No newline at end of file From 6c863293366c2f5c58aa34c9a3db6577f287ec2a Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 11:33:11 -0700 Subject: [PATCH 036/213] add apps filters events --- app/lib/pages/apps/widgets/filter_sheet.dart | 23 ++++++++++++++++++ app/lib/utils/analytics/mixpanel.dart | 25 ++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/app/lib/pages/apps/widgets/filter_sheet.dart b/app/lib/pages/apps/widgets/filter_sheet.dart index d097b9fad..27f3288c7 100644 --- a/app/lib/pages/apps/widgets/filter_sheet.dart +++ b/app/lib/pages/apps/widgets/filter_sheet.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:omi/providers/app_provider.dart'; +import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:provider/provider.dart'; class FilterBottomSheet extends StatelessWidget { @@ -50,6 +51,8 @@ class FilterBottomSheet extends StatelessWidget { label: 'Installed Apps', onTap: () { provider.addOrRemoveFilter('Installed Apps', 'Apps'); + MixpanelManager().appsTypeFilter( + 'Installed Apps', provider.isFilterSelected('Installed Apps', 'Apps')); }, isSelected: provider.isFilterSelected('Installed Apps', 'Apps'), ), @@ -57,6 +60,7 @@ class FilterBottomSheet extends StatelessWidget { label: 'My Apps', onTap: () { provider.addOrRemoveFilter('My Apps', 'Apps'); + MixpanelManager().appsTypeFilter('My Apps', provider.isFilterSelected('My Apps', 'Apps')); }, isSelected: provider.isFilterSelected('My Apps', 'Apps'), ), @@ -71,6 +75,7 @@ class FilterBottomSheet extends StatelessWidget { label: 'A-Z', onTap: () { provider.addOrRemoveFilter('A-Z', 'Sort'); + MixpanelManager().appsSortFilter('A-Z', provider.isFilterSelected('A-Z', 'Sort')); }, isSelected: provider.isFilterSelected('A-Z', 'Sort'), ), @@ -78,6 +83,7 @@ class FilterBottomSheet extends StatelessWidget { label: 'Z-A', onTap: () { provider.addOrRemoveFilter('Z-A', 'Sort'); + MixpanelManager().appsSortFilter('Z-A', provider.isFilterSelected('Z-A', 'Sort')); }, isSelected: provider.isFilterSelected('Z-A', 'Sort'), ), @@ -85,6 +91,8 @@ class FilterBottomSheet extends StatelessWidget { label: 'Highest Rating', onTap: () { provider.addOrRemoveFilter('Highest Rating', 'Sort'); + MixpanelManager().appsSortFilter( + 'Highest Rating', provider.isFilterSelected('Highest Rating', 'Sort')); }, isSelected: provider.isFilterSelected('Highest Rating', 'Sort'), ), @@ -92,6 +100,8 @@ class FilterBottomSheet extends StatelessWidget { label: 'Lowest Rating', onTap: () { provider.addOrRemoveFilter('Lowest Rating', 'Sort'); + MixpanelManager() + .appsSortFilter('Lowest Rating', provider.isFilterSelected('Lowest Rating', 'Sort')); }, isSelected: provider.isFilterSelected('Lowest Rating', 'Sort'), ), @@ -106,6 +116,8 @@ class FilterBottomSheet extends StatelessWidget { label: category.title, onTap: () { provider.addOrRemoveCategoryFilter(category); + MixpanelManager().appsCategoryFilter( + category.title, provider.isCategoryFilterSelected(category)); }, isSelected: provider.isCategoryFilterSelected(category), )) @@ -120,24 +132,32 @@ class FilterBottomSheet extends StatelessWidget { label: '1+ Stars', onTap: () { provider.addOrRemoveFilter('1+ Stars', 'Rating'); + MixpanelManager() + .appsRatingFilter('1+ Stars', provider.isFilterSelected('1+ Stars', 'Rating')); }, isSelected: provider.isFilterSelected('1+ Stars', 'Rating')), FilterOption( label: '2+ Stars', onTap: () { provider.addOrRemoveFilter('2+ Stars', 'Rating'); + MixpanelManager() + .appsRatingFilter('2+ Stars', provider.isFilterSelected('2+ Stars', 'Rating')); }, isSelected: provider.isFilterSelected('2+ Stars', 'Rating')), FilterOption( label: '3+ Stars', onTap: () { provider.addOrRemoveFilter('3+ Stars', 'Rating'); + MixpanelManager() + .appsRatingFilter('3+ Stars', provider.isFilterSelected('3+ Stars', 'Rating')); }, isSelected: provider.isFilterSelected('3+ Stars', 'Rating')), FilterOption( label: '4+ Stars', onTap: () { provider.addOrRemoveFilter('4+ Stars', 'Rating'); + MixpanelManager() + .appsRatingFilter('4+ Stars', provider.isFilterSelected('4+ Stars', 'Rating')); }, isSelected: provider.isFilterSelected('4+ Stars', 'Rating')), ], @@ -151,6 +171,8 @@ class FilterBottomSheet extends StatelessWidget { label: capability.title, onTap: () { provider.addOrRemoveCapabilityFilter(capability); + MixpanelManager().appsCapabilityFilter( + capability.title, provider.isCapabilityFilterSelected(capability)); }, isSelected: provider.isCapabilityFilterSelected(capability), )) @@ -167,6 +189,7 @@ class FilterBottomSheet extends StatelessWidget { child: ElevatedButton( onPressed: () { provider.clearFilters(); + MixpanelManager().appsClearFilters(); }, style: ElevatedButton.styleFrom( backgroundColor: Colors.grey[300], diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index 2f5be6f2c..e210080cb 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -305,4 +305,29 @@ class MixpanelManager { void deleteAccountCancelled() => track('Delete Account Cancelled'); void deleteUser() => _mixpanel?.getPeople().deleteUser(); + + // Apps Filter + void appsFilterOpened() => track('Apps Filter Opened'); + void appsFilterApplied() => track('Apps Filter Applied'); + void appsCategoryFilter(String category, bool isSelected) { + track('Apps Category Filter', properties: {'category': category, 'selected': isSelected}); + } + + void appsTypeFilter(String type, bool isSelected) { + track('Apps Type Filter', properties: {'type': type, 'selected': isSelected}); + } + + void appsSortFilter(String sortBy, bool isSelected) { + track('Apps Sort Filter', properties: {'sort_by': sortBy, 'selected': isSelected}); + } + + void appsRatingFilter(String rating, bool isSelected) { + track('Apps Rating Filter', properties: {'rating': rating, 'selected': isSelected}); + } + + void appsCapabilityFilter(String capability, bool isSelected) { + track('Apps Capability Filter', properties: {'capability': capability, 'selected': isSelected}); + } + + void appsClearFilters() => track('Apps Clear Filters'); } From 24ab4485a1fec5dd13f786bbab34bf4c4168ca54 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 12:10:01 -0700 Subject: [PATCH 037/213] improve chat event and add persona events --- app/lib/pages/chat/page.dart | 1 - app/lib/pages/persona/persona_profile.dart | 10 +- app/lib/pages/persona/persona_provider.dart | 66 +++++++++ app/lib/providers/message_provider.dart | 23 +++- app/lib/utils/analytics/mixpanel.dart | 142 +++++++++++++++++++- 5 files changed, 230 insertions(+), 12 deletions(-) diff --git a/app/lib/pages/chat/page.dart b/app/lib/pages/chat/page.dart index 879ba0963..8cd63731b 100644 --- a/app/lib/pages/chat/page.dart +++ b/app/lib/pages/chat/page.dart @@ -600,7 +600,6 @@ class ChatPageState extends State with AutomaticKeepAliveClientMixin { _sendMessageUtil(String text) { var provider = context.read(); - MixpanelManager().chatMessageSent(text, provider.uploadedFiles.isNotEmpty, provider.uploadedFiles.length); provider.setSendingMessage(true); provider.addMessageLocally(text); scrollToBottom(); diff --git a/app/lib/pages/persona/persona_profile.dart b/app/lib/pages/persona/persona_profile.dart index f9b9599ff..bcaddeb3c 100644 --- a/app/lib/pages/persona/persona_profile.dart +++ b/app/lib/pages/persona/persona_profile.dart @@ -6,16 +6,11 @@ import 'package:omi/backend/preferences.dart'; import 'package:omi/backend/schema/app.dart'; import 'package:omi/gen/assets.gen.dart'; import 'package:omi/main.dart'; -import 'package:omi/pages/chat/clone_chat_page.dart'; import 'package:omi/pages/onboarding/wrapper.dart'; import 'package:omi/pages/persona/persona_provider.dart'; -import 'package:omi/providers/app_provider.dart'; import 'package:omi/providers/auth_provider.dart'; import 'package:omi/providers/home_provider.dart'; import 'package:omi/pages/persona/twitter/social_profile.dart'; -import 'package:omi/pages/settings/page.dart'; -import 'package:omi/providers/capture_provider.dart'; -import 'package:omi/providers/message_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:posthog_flutter/posthog_flutter.dart'; @@ -46,6 +41,7 @@ class _PersonaProfilePageState extends State { void initState() { WidgetsBinding.instance.addPostFrameCallback((_) async { final provider = Provider.of(context, listen: false); + String source = 'unknown'; // Default source // Check if we came from settings final isFromSettings = ModalRoute.of(context)?.settings.arguments == 'from_settings'; @@ -55,8 +51,10 @@ class _PersonaProfilePageState extends State { if (provider.routing == PersonaProfileRouting.apps_updates && provider.userPersona != null) { provider.prepareUpdatePersona(provider.userPersona!); + MixpanelManager().personaProfileViewed(personaId: provider.userPersona!.id, source: source); } else { await provider.getVerifiedUserPersona(); + MixpanelManager().personaProfileViewed(personaId: provider.userPersona?.id, source: source); } }); super.initState(); @@ -269,6 +267,8 @@ class _PersonaProfilePageState extends State { await Posthog().capture(eventName: 'share_persona_clicked', properties: { 'persona_username': persona.username ?? '', }); + MixpanelManager() + .personaShared(personaId: persona.id, personaUsername: persona.username); Share.share( 'https://personas.omi.me/u/${persona.username}', subject: '${persona.getName()} Persona', diff --git a/app/lib/pages/persona/persona_provider.dart b/app/lib/pages/persona/persona_provider.dart index b2d74b613..8c1ae19c7 100644 --- a/app/lib/pages/persona/persona_provider.dart +++ b/app/lib/pages/persona/persona_provider.dart @@ -6,6 +6,7 @@ import 'package:omi/backend/preferences.dart'; import 'package:omi/backend/schema/app.dart'; import 'package:omi/utils/alerts/app_snackbar.dart'; import 'package:image_picker/image_picker.dart'; +import 'package:omi/utils/analytics/mixpanel.dart'; typedef ShowSuccessDialogCallback = void Function(String url); @@ -77,12 +78,17 @@ class PersonaProvider extends ChangeNotifier { if (res['status'] == 'notfound') { AppSnackbar.showSnackbarError('Twitter handle not found'); _twitterProfile = {}; + MixpanelManager().personaTwitterProfileFetched(twitterHandle: handle, fetchSuccessful: false); } else if (res['status'] == 'suspended') { AppSnackbar.showSnackbarError('Twitter handle is suspended'); _twitterProfile = {}; + MixpanelManager().personaTwitterProfileFetched(twitterHandle: handle, fetchSuccessful: false); } else { _twitterProfile = res; + MixpanelManager().personaTwitterProfileFetched(twitterHandle: handle, fetchSuccessful: true); } + } else { + MixpanelManager().personaTwitterProfileFetched(twitterHandle: handle, fetchSuccessful: false); } setIsLoading(false); notifyListeners(); @@ -93,6 +99,10 @@ class PersonaProvider extends ChangeNotifier { if (!verified) { AppSnackbar.showSnackbarError('Failed to verify Twitter handle'); } + MixpanelManager().personaTwitterOwnershipVerified( + personaId: verifiedPersonaId ?? personaId, + twitterHandle: _twitterProfile['profile'], + verificationSuccessful: verified); SharedPreferencesUtil().hasPersonaCreated = true; SharedPreferencesUtil().verifiedPersonaId = verifiedPersonaId; toggleTwitterConnection(true); @@ -158,6 +168,9 @@ class PersonaProvider extends ChangeNotifier { // Update debugPrint("setPersonaPublic"); + if (_userPersona != null) { + MixpanelManager().personaPublicToggled(personaId: _userPersona!.id, isPublic: makePersonaPublic); + } updatePersona(); } @@ -180,6 +193,7 @@ class PersonaProvider extends ChangeNotifier { final XFile? image = await picker.pickImage(source: ImageSource.gallery); if (image != null) { selectedImage = File(image.path); + MixpanelManager().personaCreateImagePicked(); validateForm(); } notifyListeners(); @@ -190,6 +204,11 @@ class PersonaProvider extends ChangeNotifier { final XFile? image = await picker.pickImage(source: ImageSource.gallery); if (image != null) { selectedImage = File(image.path); + if (_userPersona != null) { + MixpanelManager().personaUpdateImagePicked(personaId: _userPersona!.id); + } else { + MixpanelManager().personaCreateImagePicked(); + } validateForm(); // Update @@ -224,6 +243,9 @@ class PersonaProvider extends ChangeNotifier { void toggleOmiConnection(bool value) { hasOmiConnection = value; + if (_userPersona != null) { + MixpanelManager().personaOmiConnectionToggled(personaId: _userPersona!.id, omiConnected: value); + } notifyListeners(); } @@ -232,6 +254,9 @@ class PersonaProvider extends ChangeNotifier { if (!value) { _twitterProfile = {}; } + if (_userPersona != null) { + MixpanelManager().personaTwitterConnectionToggled(personaId: _userPersona!.id, twitterConnected: value); + } notifyListeners(); } @@ -242,6 +267,9 @@ class PersonaProvider extends ChangeNotifier { debugPrint("disconnectTwitter"); if (_isEditablePersona()) { updatePersona(); + if (_userPersona != null) { + MixpanelManager().personaTwitterConnectionToggled(personaId: _userPersona!.id, twitterConnected: false); + } } notifyListeners(); } @@ -251,6 +279,9 @@ class PersonaProvider extends ChangeNotifier { debugPrint("disconnectOmi"); if (_isEditablePersona()) { updatePersona(); + if (_userPersona != null) { + MixpanelManager().personaOmiConnectionToggled(personaId: _userPersona!.id, omiConnected: false); + } } notifyListeners(); } @@ -265,6 +296,7 @@ class PersonaProvider extends ChangeNotifier { return; } + MixpanelManager().personaUpdateStarted(personaId: _userPersona!.id); setIsLoading(true); try { Map personaData = { @@ -297,23 +329,42 @@ class PersonaProvider extends ChangeNotifier { _userPersona!.connectedAccounts.where((element) => element != 'twitter').toList(); } + // Determine updated fields (example, more robust checking needed) + List updatedFields = []; + if (personaData['name'] != _userPersona!.name) updatedFields.add('name'); + if (personaData['username'] != _userPersona!.username) updatedFields.add('username'); + if (personaData['private'] == _userPersona!.private) + updatedFields.add('privacy'); // private is !makePersonaPublic + if (selectedImage != null) updatedFields.add('image'); + bool success = await updatePersonaApp(selectedImage, personaData); if (success) { AppSnackbar.showSnackbarSuccess('Persona updated successfully'); + MixpanelManager().personaUpdated( + personaId: _userPersona!.id, + isPublic: !(personaData['private'] as bool? ?? true), + updatedFields: updatedFields, + connectedAccounts: personaData['connected_accounts'] as List?, + hasOmiConnection: (personaData['connected_accounts'] as List?)?.contains('omi'), + hasTwitterConnection: (personaData['connected_accounts'] as List?)?.contains('twitter')); await getVerifiedUserPersona(); notifyListeners(); } else { AppSnackbar.showSnackbarError('Failed to update persona'); + MixpanelManager() + .personaUpdateFailed(personaId: _userPersona!.id, errorMessage: 'Failed to update persona API call'); } } catch (e) { print('Error updating persona: $e'); AppSnackbar.showSnackbarError('Failed to update persona'); + MixpanelManager().personaUpdateFailed(personaId: _userPersona!.id, errorMessage: e.toString()); } finally { setIsLoading(false); } } Future createPersona() async { + MixpanelManager().personaCreateStarted(); if (!formKey.currentState!.validate() || selectedImage == null) { if (selectedImage == null) { AppSnackbar.showSnackbarError('Please select an image'); @@ -353,14 +404,23 @@ class PersonaProvider extends ChangeNotifier { if (res.isNotEmpty) { String personaUrl = 'personas.omi.me/u/${res['username']}'; debugPrint('Persona URL: $personaUrl'); + MixpanelManager().personaCreated( + personaId: res['id'], + isPublic: !(personaData['private'] as bool? ?? true), + connectedAccounts: personaData['connected_accounts'] as List?, + hasOmiConnection: (personaData['connected_accounts'] as List?)?.contains('omi'), + hasTwitterConnection: (personaData['connected_accounts'] as List?)?.contains('twitter')); if (onShowSuccessDialog != null) { onShowSuccessDialog!(personaUrl); } } else { AppSnackbar.showSnackbarError('Failed to create your persona. Please try again later.'); + MixpanelManager().personaCreateFailed(errorMessage: 'API response empty or no ID'); } } catch (e) { AppSnackbar.showSnackbarError('Failed to create persona: $e'); + MixpanelManager().personaCreateFailed(errorMessage: e.toString()); + setIsLoading(false); } finally { setIsLoading(false); } @@ -369,6 +429,7 @@ class PersonaProvider extends ChangeNotifier { Future checkIsUsernameTaken(String username) async { setIsCheckingUsername(true); isUsernameTaken = await checkPersonaUsername(username); + MixpanelManager().personaUsernameCheck(username: username, isTaken: isUsernameTaken); setIsCheckingUsername(false); } @@ -390,13 +451,18 @@ class PersonaProvider extends ChangeNotifier { try { var enabled = await enableAppServer(_userPersona!.id); if (enabled) { + MixpanelManager().personaEnabled(personaId: _userPersona!.id); return true; } else { AppSnackbar.showSnackbarError('Failed to enable persona'); + MixpanelManager().personaEnableFailed(personaId: _userPersona!.id, errorMessage: 'API returned false'); return false; } } catch (e) { AppSnackbar.showSnackbarError('Error enabling persona: $e'); + if (_userPersona != null) { + MixpanelManager().personaEnableFailed(personaId: _userPersona!.id, errorMessage: e.toString()); + } return false; } finally { setIsLoading(false); diff --git a/app/lib/providers/message_provider.dart b/app/lib/providers/message_provider.dart index 4375175fe..7e48ebb2e 100644 --- a/app/lib/providers/message_provider.dart +++ b/app/lib/providers/message_provider.dart @@ -14,6 +14,7 @@ import 'package:omi/providers/app_provider.dart'; import 'package:omi/utils/alerts/app_snackbar.dart'; import 'package:image_picker/image_picker.dart'; import 'package:omi/utils/file.dart'; +import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:uuid/uuid.dart'; class MessageProvider extends ChangeNotifier { @@ -333,18 +334,30 @@ class MessageProvider extends ChangeNotifier { Future sendMessageStreamToServer(String text) async { setShowTypingIndicator(true); - var appId = appProvider?.selectedChatAppId; - if (appId == 'no_selected') { - appId = null; + var currentAppId = appProvider?.selectedChatAppId; + if (currentAppId == 'no_selected') { + currentAppId = null; } - var message = ServerMessage.empty(appId: appId); + + String chatTargetId = currentAppId ?? 'omi'; + App? targetApp = currentAppId != null ? appProvider?.apps.firstWhereOrNull((app) => app.id == currentAppId) : null; + bool isPersonaChat = targetApp != null ? !targetApp.isNotPersona() : false; + + MixpanelManager().chatMessageSent( + message: text, + includesFiles: uploadedFiles.isNotEmpty, + numberOfFiles: uploadedFiles.length, + chatTargetId: chatTargetId, + isPersonaChat: isPersonaChat); + + var message = ServerMessage.empty(appId: currentAppId); messages.insert(0, message); notifyListeners(); List fileIds = uploadedFiles.map((e) => e.id).toList(); clearSelectedFiles(); clearUploadedFiles(); try { - await for (var chunk in sendMessageStreamServer(text, appId: appProvider?.selectedChatAppId, filesId: fileIds)) { + await for (var chunk in sendMessageStreamServer(text, appId: currentAppId, filesId: fileIds)) { if (chunk.type == MessageChunkType.think) { message.thinkings.add(chunk.text); notifyListeners(); diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index e210080cb..8de86b2b0 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -208,12 +208,20 @@ class MixpanelManager { void conversationDeleted(ServerConversation conversation) => track('Memory Deleted', properties: getConversationEventProperties(conversation)); - void chatMessageSent(String message, bool includesFiles, int numberOfFiles) => + void chatMessageSent({ + required String message, + required bool includesFiles, + required int numberOfFiles, + required String chatTargetId, + required bool isPersonaChat, + }) => track('Chat Message Sent', properties: { 'message_length': message.length, 'message_word_count': message.split(' ').length, 'includes_files': includesFiles, 'number_of_files': numberOfFiles, + 'chat_target_id': chatTargetId, + 'is_persona_chat': isPersonaChat, }); void speechProfileCapturePageClicked() => track('Speech Profile Capture Page Clicked'); @@ -330,4 +338,136 @@ class MixpanelManager { } void appsClearFilters() => track('Apps Clear Filters'); + + // Persona Events + void personaProfileViewed({String? personaId, required String source}) { + track('Persona Profile Viewed', properties: { + if (personaId != null) 'persona_id': personaId, + 'source': source, + }); + } + + void personaCreateStarted() => track('Persona Create Started'); + + void personaCreateImagePicked() => track('Persona Create Image Picked'); + + void personaCreated({ + required String personaId, + required bool isPublic, + List? connectedAccounts, + bool? hasOmiConnection, + bool? hasTwitterConnection, + }) { + track('Persona Created', properties: { + 'persona_id': personaId, + 'is_public': isPublic, + if (connectedAccounts != null) 'connected_accounts': connectedAccounts, + if (hasOmiConnection != null) 'has_omi_connection': hasOmiConnection, + if (hasTwitterConnection != null) 'has_twitter_connection': hasTwitterConnection, + }); + } + + void personaCreateFailed({String? errorMessage}) { + track('Persona Create Failed', properties: { + if (errorMessage != null) 'error_message': errorMessage, + }); + } + + void personaUpdateStarted({required String personaId}) { + track('Persona Update Started', properties: {'persona_id': personaId}); + } + + void personaUpdateImagePicked({required String personaId}) { + track('Persona Update Image Picked', properties: {'persona_id': personaId}); + } + + void personaUpdated({ + required String personaId, + List? updatedFields, + required bool isPublic, + List? connectedAccounts, + bool? hasOmiConnection, + bool? hasTwitterConnection, + }) { + track('Persona Updated', properties: { + 'persona_id': personaId, + if (updatedFields != null && updatedFields.isNotEmpty) 'updated_fields': updatedFields, + 'is_public': isPublic, + if (connectedAccounts != null) 'connected_accounts': connectedAccounts, + if (hasOmiConnection != null) 'has_omi_connection': hasOmiConnection, + if (hasTwitterConnection != null) 'has_twitter_connection': hasTwitterConnection, + }); + } + + void personaUpdateFailed({required String personaId, String? errorMessage}) { + track('Persona Update Failed', properties: { + 'persona_id': personaId, + if (errorMessage != null) 'error_message': errorMessage, + }); + } + + void personaPublicToggled({required String personaId, required bool isPublic}) { + track('Persona Public Toggled', properties: { + 'persona_id': personaId, + 'is_public': isPublic, + }); + } + + void personaOmiConnectionToggled({required String personaId, required bool omiConnected}) { + track('Persona OMI Connection Toggled', properties: { + 'persona_id': personaId, + 'omi_connected': omiConnected, + }); + } + + void personaTwitterConnectionToggled({required String personaId, required bool twitterConnected}) { + track('Persona Twitter Connection Toggled', properties: { + 'persona_id': personaId, + 'twitter_connected': twitterConnected, + }); + } + + void personaTwitterProfileFetched({required String twitterHandle, required bool fetchSuccessful}) { + track('Persona Twitter Profile Fetched', properties: { + 'twitter_handle': twitterHandle, + 'fetch_successful': fetchSuccessful, + }); + } + + void personaTwitterOwnershipVerified({ + String? personaId, + required String twitterHandle, + required bool verificationSuccessful, + }) { + track('Persona Twitter Ownership Verified', properties: { + if (personaId != null) 'persona_id': personaId, + 'twitter_handle': twitterHandle, + 'verification_successful': verificationSuccessful, + }); + } + + void personaShared({required String? personaId, required String? personaUsername}) { + track('Persona Shared', properties: { + if (personaId != null) 'persona_id': personaId, + if (personaUsername != null) 'persona_username': personaUsername, + }); + } + + void personaUsernameCheck({required String username, required bool isTaken}) { + track('Persona Username Check', properties: { + 'username': username, + 'is_taken': isTaken, + }); + } + + void personaEnabled({required String personaId}) { + track('Persona Enabled', properties: {'persona_id': personaId}); + } + + void personaEnableFailed({required String personaId, String? errorMessage}) { + track('Persona Enable Failed', properties: { + 'persona_id': personaId, + if (errorMessage != null) 'error_message': errorMessage, + }); + } } From 82dc347acabf5147bea8ef2cbbe87dd007e7edf6 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 12:11:56 -0700 Subject: [PATCH 038/213] misc --- app/lib/pages/persona/persona_provider.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/lib/pages/persona/persona_provider.dart b/app/lib/pages/persona/persona_provider.dart index 8c1ae19c7..d03d1f00e 100644 --- a/app/lib/pages/persona/persona_provider.dart +++ b/app/lib/pages/persona/persona_provider.dart @@ -329,12 +329,12 @@ class PersonaProvider extends ChangeNotifier { _userPersona!.connectedAccounts.where((element) => element != 'twitter').toList(); } - // Determine updated fields (example, more robust checking needed) List updatedFields = []; if (personaData['name'] != _userPersona!.name) updatedFields.add('name'); if (personaData['username'] != _userPersona!.username) updatedFields.add('username'); - if (personaData['private'] == _userPersona!.private) - updatedFields.add('privacy'); // private is !makePersonaPublic + if (personaData['private'] == _userPersona!.private) { + updatedFields.add('privacy'); + } if (selectedImage != null) updatedFields.add('image'); bool success = await updatePersonaApp(selectedImage, personaData); From 367ab5bd77b490cc2662e4e5e7a147b2a6e9b9a4 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 12:19:16 -0700 Subject: [PATCH 039/213] track summarised app sheets usage --- .../widgets/summarized_apps_sheet.dart | 30 ++++++++++++++++++- app/lib/utils/analytics/mixpanel.dart | 29 ++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/app/lib/pages/conversation_detail/widgets/summarized_apps_sheet.dart b/app/lib/pages/conversation_detail/widgets/summarized_apps_sheet.dart index c51903acb..61b73623d 100644 --- a/app/lib/pages/conversation_detail/widgets/summarized_apps_sheet.dart +++ b/app/lib/pages/conversation_detail/widgets/summarized_apps_sheet.dart @@ -24,6 +24,12 @@ class SummarizedAppsBottomSheet extends StatelessWidget { builder: (context, provider, _) { final summarizedApp = provider.getSummarizedApp(); final currentAppId = summarizedApp?.appId; + final conversationId = provider.conversation.id; + + MixpanelManager().summarizedAppSheetViewed( + conversationId: conversationId, + currentSummarizedAppId: currentAppId, + ); return _SheetContainer( scrollController: scrollController, @@ -146,6 +152,15 @@ class _AppsList extends StatelessWidget { void _handleAutoAppTap(BuildContext context) async { Navigator.pop(context); final provider = context.read(); + final previousAppId = provider.getSummarizedApp()?.appId; + final conversationId = provider.conversation.id; + + MixpanelManager().summarizedAppSelected( + conversationId: conversationId, + selectedAppId: 'auto', + previousAppId: previousAppId, + ); + provider.clearSelectedAppForReprocessing(); await provider.reprocessConversation(); return; @@ -153,9 +168,18 @@ class _AppsList extends StatelessWidget { void _handleAppTap(BuildContext context, App app) async { // If this is a different app than currently selected, reprocess with this app + final provider = context.read(); + final previousAppId = provider.getSummarizedApp()?.appId; + final conversationId = provider.conversation.id; + if (app.id != currentAppId) { + MixpanelManager().summarizedAppSelected( + conversationId: conversationId, + selectedAppId: app.id, + previousAppId: previousAppId, + ); + Navigator.pop(context); - final provider = context.read(); provider.setSelectedAppForReprocessing(app); provider.setPreferredSummarizationApp(app.id); await provider.reprocessConversation(appId: app.id); @@ -277,6 +301,10 @@ class _EnableAppsListItem extends StatelessWidget { trailing: const Icon(Icons.arrow_forward_ios, color: Colors.white, size: 16), onTap: () { Navigator.pop(context); + final conversationId = context.read().conversation?.id; + if (conversationId != null) { + MixpanelManager().summarizedAppEnableAppsClicked(conversationId: conversationId); + } routeToPage(context, const AppsPage(showAppBar: true)); MixpanelManager().pageOpened('Detail Apps'); }, diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index 8de86b2b0..f42ee9621 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -470,4 +470,33 @@ class MixpanelManager { if (errorMessage != null) 'error_message': errorMessage, }); } + + // Summarized Apps Sheet Events + void summarizedAppSheetViewed({ + required String conversationId, + String? currentSummarizedAppId, + }) { + track('Summarized App Sheet Viewed', properties: { + 'conversation_id': conversationId, + 'current_summarized_app_id': currentSummarizedAppId ?? 'auto', + }); + } + + void summarizedAppSelected({ + required String conversationId, + required String selectedAppId, + String? previousAppId, + }) { + track('Summarized App Selected', properties: { + 'conversation_id': conversationId, + 'selected_app_id': selectedAppId, + 'previous_app_id': previousAppId ?? 'auto', + }); + } + + void summarizedAppEnableAppsClicked({required String conversationId}) { + track('Summarized App Enable Apps Clicked', properties: { + 'conversation_id': conversationId, + }); + } } From c7647fe5d21dfbb2670328f491297a97074bd50d Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 12:36:28 -0700 Subject: [PATCH 040/213] add events to track voice input usage --- app/lib/pages/chat/page.dart | 1 + app/lib/providers/message_provider.dart | 35 ++++++++++++++++++++----- app/lib/utils/analytics/mixpanel.dart | 9 +++++++ 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/app/lib/pages/chat/page.dart b/app/lib/pages/chat/page.dart index 8cd63731b..8a6c42bc7 100644 --- a/app/lib/pages/chat/page.dart +++ b/app/lib/pages/chat/page.dart @@ -499,6 +499,7 @@ class ChatPageState extends State with AutomaticKeepAliveClientMixin { setState(() { textController.text = transcript; _showVoiceRecorder = false; + context.read().setNextMessageOriginIsVoice(true); }); }, onClose: () { diff --git a/app/lib/providers/message_provider.dart b/app/lib/providers/message_provider.dart index 7e48ebb2e..0c4cc1b1d 100644 --- a/app/lib/providers/message_provider.dart +++ b/app/lib/providers/message_provider.dart @@ -20,6 +20,7 @@ import 'package:uuid/uuid.dart'; class MessageProvider extends ChangeNotifier { AppProvider? appProvider; List messages = []; + bool _isNextMessageFromVoice = false; bool isLoadingMessages = false; bool hasCachedMessages = false; @@ -39,6 +40,10 @@ class MessageProvider extends ChangeNotifier { appProvider = p; } + void setNextMessageOriginIsVoice(bool isVoice) { + _isNextMessageFromVoice = isVoice; + } + void setIsUploadingFiles() { if (uploadingFiles.values.contains(true)) { isUploadingFiles = true; @@ -278,6 +283,19 @@ class MessageProvider extends ChangeNotifier { codec?.getFrameSize() ?? 160, ); + var currentAppId = appProvider?.selectedChatAppId; + if (currentAppId == 'no_selected') { + currentAppId = null; + } + String chatTargetId = currentAppId ?? 'omi'; + App? targetApp = currentAppId != null ? appProvider?.apps.firstWhereOrNull((app) => app.id == currentAppId) : null; + bool isPersonaChat = targetApp != null ? !targetApp.isNotPersona() : false; + + MixpanelManager().chatVoiceInputUsed( + chatTargetId: chatTargetId, + isPersonaChat: isPersonaChat, + ); + setShowTypingIndicator(true); var message = ServerMessage.empty(); messages.insert(0, message); @@ -344,11 +362,14 @@ class MessageProvider extends ChangeNotifier { bool isPersonaChat = targetApp != null ? !targetApp.isNotPersona() : false; MixpanelManager().chatMessageSent( - message: text, - includesFiles: uploadedFiles.isNotEmpty, - numberOfFiles: uploadedFiles.length, - chatTargetId: chatTargetId, - isPersonaChat: isPersonaChat); + message: text, + includesFiles: uploadedFiles.isNotEmpty, + numberOfFiles: uploadedFiles.length, + chatTargetId: chatTargetId, + isPersonaChat: isPersonaChat, + isVoiceInput: _isNextMessageFromVoice, + ); + _isNextMessageFromVoice = false; var message = ServerMessage.empty(appId: currentAppId); messages.insert(0, message); @@ -391,11 +412,11 @@ class MessageProvider extends ChangeNotifier { setShowTypingIndicator(false); } - Future sendMessageToServer(String message, String? appId) async { + Future sendMessageToServer(String text, String? appId) async { setShowTypingIndicator(true); messages.insert(0, ServerMessage.empty(appId: appId)); List fileIds = uploadedFiles.map((e) => e.id).toList(); - var mes = await sendMessageServer(message, appId: appId, fileIds: fileIds); + var mes = await sendMessageServer(text, appId: appId, fileIds: fileIds); if (messages[0].id == '0000') { messages[0] = mes; } diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index f42ee9621..aa176959e 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -214,6 +214,7 @@ class MixpanelManager { required int numberOfFiles, required String chatTargetId, required bool isPersonaChat, + required bool isVoiceInput, }) => track('Chat Message Sent', properties: { 'message_length': message.length, @@ -222,8 +223,16 @@ class MixpanelManager { 'number_of_files': numberOfFiles, 'chat_target_id': chatTargetId, 'is_persona_chat': isPersonaChat, + 'is_voice_input': isVoiceInput, }); + void chatVoiceInputUsed({required String chatTargetId, required bool isPersonaChat}) { + track('Chat Voice Input Used', properties: { + 'chat_target_id': chatTargetId, + 'is_persona_chat': isPersonaChat, + }); + } + void speechProfileCapturePageClicked() => track('Speech Profile Capture Page Clicked'); void showDiscardedMemoriesToggled(bool showDiscarded) => From 4217305d2029186fef44dfb893ca92344b19de8d Mon Sep 17 00:00:00 2001 From: Nik Shevchenko <43514161+kodjima33@users.noreply.github.com> Date: Wed, 14 May 2025 13:33:28 -0700 Subject: [PATCH 041/213] Update Introduction.mdx --- docs/docs/developer/apps/Introduction.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/developer/apps/Introduction.mdx b/docs/docs/developer/apps/Introduction.mdx index a01ce1dfa..b827ef3c7 100644 --- a/docs/docs/developer/apps/Introduction.mdx +++ b/docs/docs/developer/apps/Introduction.mdx @@ -22,7 +22,7 @@ Create webhook using [webhook.site](https://webhook.site) and copy this url -In omi App: +In omi App, select "connect omi device" and then: | Explore => Create an App | Select Capability | Paste Webhook URL | Install App | |-------------------------|-------------------|-------------------|--------------| From 4998bd2a6f7d5244271846e1a3a52d3ecdba8e77 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 13:38:55 -0700 Subject: [PATCH 042/213] add AutomaticKeepAliveClientMixin and hide bottom nav while searching memories --- app/lib/pages/home/page.dart | 25 +++++++++++++++++++------ app/lib/providers/home_provider.dart | 6 ++++++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index c2ffe4223..e168cf02b 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -210,7 +210,8 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker await Provider.of(context, listen: false).setUserPeople(); } if (mounted) { - await Provider.of(context, listen: false).streamDeviceRecording(device: Provider.of(context, listen: false).connectedDevice); + await Provider.of(context, listen: false) + .streamDeviceRecording(device: Provider.of(context, listen: false).connectedDevice); } // Navigate @@ -384,7 +385,10 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker ), Consumer( builder: (context, home, child) { - if (home.chatFieldFocusNode.hasFocus || home.convoSearchFieldFocusNode.hasFocus || home.appsSearchFieldFocusNode.hasFocus) { + if (home.isChatFieldFocused || + home.isConvoSearchFieldFocused || + home.isAppsSearchFieldFocused || + home.isMemoriesSearchFieldFocused) { return const SizedBox.shrink(); } else { return Align( @@ -396,7 +400,12 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker color: Colors.black, borderRadius: BorderRadius.all(Radius.circular(18)), border: GradientBoxBorder( - gradient: LinearGradient(colors: [Color.fromARGB(127, 208, 208, 208), Color.fromARGB(127, 188, 99, 121), Color.fromARGB(127, 86, 101, 182), Color.fromARGB(127, 126, 190, 236)]), + gradient: LinearGradient(colors: [ + Color.fromARGB(127, 208, 208, 208), + Color.fromARGB(127, 188, 99, 121), + Color.fromARGB(127, 86, 101, 182), + Color.fromARGB(127, 126, 190, 236) + ]), width: 2, ), shape: BoxShape.rectangle, @@ -405,13 +414,15 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker labelPadding: const EdgeInsets.symmetric(vertical: 10), indicatorPadding: EdgeInsets.zero, onTap: (index) { - MixpanelManager().bottomNavigationTabClicked(['Memories', 'Chat', 'Explore', 'Memories'][index]); + MixpanelManager() + .bottomNavigationTabClicked(['Memories', 'Chat', 'Explore', 'Facts'][index]); primaryFocus?.unfocus(); if (home.selectedIndex == index) { return; } home.setIndex(index); - _controller?.animateToPage(index, duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); + _controller?.animateToPage(index, + duration: const Duration(milliseconds: 200), curve: Curves.easeInOut); }, indicatorColor: Colors.transparent, tabs: [ @@ -609,7 +620,9 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker bool hasSpeech = SharedPreferencesUtil().hasSpeakerProfile; String transcriptModel = SharedPreferencesUtil().transcriptionModel; routeToPage(context, const SettingsPage()); - if (language != SharedPreferencesUtil().userPrimaryLanguage || hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || transcriptModel != SharedPreferencesUtil().transcriptionModel) { + if (language != SharedPreferencesUtil().userPrimaryLanguage || + hasSpeech != SharedPreferencesUtil().hasSpeakerProfile || + transcriptModel != SharedPreferencesUtil().transcriptionModel) { if (context.mounted) { context.read().onRecordProfileSettingChanged(); } diff --git a/app/lib/providers/home_provider.dart b/app/lib/providers/home_provider.dart index 3051013e7..83c4d7427 100644 --- a/app/lib/providers/home_provider.dart +++ b/app/lib/providers/home_provider.dart @@ -12,9 +12,11 @@ class HomeProvider extends ChangeNotifier { final FocusNode chatFieldFocusNode = FocusNode(); final FocusNode appsSearchFieldFocusNode = FocusNode(); final FocusNode convoSearchFieldFocusNode = FocusNode(); + final FocusNode memoriesSearchFieldFocusNode = FocusNode(); bool isAppsSearchFieldFocused = false; bool isChatFieldFocused = false; bool isConvoSearchFieldFocused = false; + bool isMemoriesSearchFieldFocused = false; bool hasSpeakerProfile = true; bool isLoading = false; String userPrimaryLanguage = SharedPreferencesUtil().userPrimaryLanguage; @@ -67,12 +69,14 @@ class HomeProvider extends ChangeNotifier { chatFieldFocusNode.addListener(_onFocusChange); appsSearchFieldFocusNode.addListener(_onFocusChange); convoSearchFieldFocusNode.addListener(_onFocusChange); + memoriesSearchFieldFocusNode.addListener(_onFocusChange); } void _onFocusChange() { isChatFieldFocused = chatFieldFocusNode.hasFocus; isAppsSearchFieldFocused = appsSearchFieldFocusNode.hasFocus; isConvoSearchFieldFocused = convoSearchFieldFocusNode.hasFocus; + isMemoriesSearchFieldFocused = memoriesSearchFieldFocusNode.hasFocus; notifyListeners(); } @@ -177,6 +181,8 @@ class HomeProvider extends ChangeNotifier { chatFieldFocusNode.removeListener(_onFocusChange); appsSearchFieldFocusNode.removeListener(_onFocusChange); convoSearchFieldFocusNode.removeListener(_onFocusChange); + memoriesSearchFieldFocusNode.removeListener(_onFocusChange); + memoriesSearchFieldFocusNode.dispose(); chatFieldFocusNode.dispose(); appsSearchFieldFocusNode.dispose(); convoSearchFieldFocusNode.dispose(); From 82c75ca446ac2b83dc6210d740f9ca42c5d68a2d Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 13:48:38 -0700 Subject: [PATCH 043/213] improve memories management and ui --- app/lib/pages/memories/page.dart | 229 ++++++++++++------ .../memories/widgets/memory_review_sheet.dart | 1 + 2 files changed, 151 insertions(+), 79 deletions(-) diff --git a/app/lib/pages/memories/page.dart b/app/lib/pages/memories/page.dart index e957aa919..f0702d3ca 100644 --- a/app/lib/pages/memories/page.dart +++ b/app/lib/pages/memories/page.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:omi/backend/schema/memory.dart'; +import 'package:omi/providers/home_provider.dart'; import 'package:omi/providers/memories_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/ui_guidelines.dart'; @@ -12,7 +13,6 @@ import 'widgets/memory_item.dart'; import 'widgets/memory_dialog.dart'; import 'widgets/memory_review_sheet.dart'; import 'widgets/memory_management_sheet.dart'; -import 'widgets/category_chip.dart'; class MemoriesPage extends StatefulWidget { const MemoriesPage({super.key}); @@ -21,7 +21,36 @@ class MemoriesPage extends StatefulWidget { State createState() => MemoriesPageState(); } -class MemoriesPageState extends State { +class _ReviewPromptHeaderDelegate extends SliverPersistentHeaderDelegate { + final double height; + final Widget child; + + _ReviewPromptHeaderDelegate({ + required this.height, + required this.child, + }); + + @override + double get minExtent => height; + + @override + double get maxExtent => height; + + @override + Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { + return SizedBox.expand(child: child); + } + + @override + bool shouldRebuild(_ReviewPromptHeaderDelegate oldDelegate) { + return height != oldDelegate.height || child != oldDelegate.child; + } +} + +class MemoriesPageState extends State with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + final TextEditingController _searchController = TextEditingController(); MemoryCategory? _selectedCategory; final ScrollController _scrollController = ScrollController(); @@ -35,23 +64,23 @@ class MemoriesPageState extends State { @override void initState() { - () async { - await context.read().init(); + super.initState(); + (() async { + final provider = context.read(); + await provider.init(); - final unreviewedMemories = context.read().unreviewed; + if (!mounted) return; + final unreviewedMemories = provider.unreviewed; if (unreviewedMemories.isNotEmpty) { - _showReviewSheet(unreviewedMemories); + _showReviewSheet(context, unreviewedMemories, provider); } - }.withPostFrameCallback(); - super.initState(); + }).withPostFrameCallback(); } void _filterByCategory(MemoryCategory? category) { setState(() { _selectedCategory = category; }); - - // Apply category filter to provider context.read().setCategoryFilter(category); } @@ -65,11 +94,9 @@ class MemoriesPageState extends State { @override Widget build(BuildContext context) { + super.build(context); return Consumer( builder: (context, provider, _) { - final unreviewedCount = provider.unreviewed.length; - final categoryCounts = _getCategoryCounts(provider.memories); - return PopScope( canPop: true, child: Scaffold( @@ -83,63 +110,62 @@ class MemoriesPageState extends State { controller: _scrollController, headerSliverBuilder: (context, innerBoxIsScrolled) { return [ - // Top row with search bar and action buttons SliverToBoxAdapter( child: Padding( padding: const EdgeInsets.fromLTRB(16, 12, 16, 10), child: Row( children: [ - // Search bar taking most of the space - Expanded( - child: SizedBox( - height: 44, // Match button height - child: SearchBar( - hintText: 'Search memories', - leading: const Padding( - padding: EdgeInsets.only(left: 6.0), - child: Icon(FontAwesomeIcons.magnifyingGlass, color: Colors.white70, size: 14), - ), - backgroundColor: WidgetStateProperty.all(AppStyles.backgroundSecondary), - elevation: WidgetStateProperty.all(0), - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric(horizontal: 12, vertical: 4), // Reduce vertical padding - ), - controller: _searchController, - trailing: provider.searchQuery.isNotEmpty - ? [ - IconButton( - icon: const Icon(Icons.close, color: Colors.white70, size: 16), - padding: EdgeInsets.zero, - constraints: const BoxConstraints( - minHeight: 36, - minWidth: 36, - ), - onPressed: () { - _searchController.clear(); - setState(() {}); - provider.setSearchQuery(''); - }, - ) - ] - : null, - hintStyle: WidgetStateProperty.all( - TextStyle(color: AppStyles.textTertiary, fontSize: 14), - ), - textStyle: WidgetStateProperty.all( - TextStyle(color: AppStyles.textPrimary, fontSize: 14), - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(AppStyles.radiusLarge), + Consumer(builder: (context, home, child) { + return Expanded( + child: SizedBox( + height: 44, + child: SearchBar( + hintText: 'Search memories', + leading: const Padding( + padding: EdgeInsets.only(left: 6.0), + child: + Icon(FontAwesomeIcons.magnifyingGlass, color: Colors.white70, size: 14), + ), + backgroundColor: WidgetStateProperty.all(AppStyles.backgroundSecondary), + elevation: WidgetStateProperty.all(0), + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(horizontal: 12, vertical: 4), + ), + focusNode: home.memoriesSearchFieldFocusNode, + controller: _searchController, + trailing: provider.searchQuery.isNotEmpty + ? [ + IconButton( + icon: const Icon(Icons.close, color: Colors.white70, size: 16), + padding: EdgeInsets.zero, + constraints: const BoxConstraints( + minHeight: 36, + minWidth: 36, + ), + onPressed: () { + _searchController.clear(); + provider.setSearchQuery(''); + }, + ) + ] + : null, + hintStyle: WidgetStateProperty.all( + TextStyle(color: AppStyles.textTertiary, fontSize: 14), + ), + textStyle: WidgetStateProperty.all( + TextStyle(color: AppStyles.textPrimary, fontSize: 14), ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(AppStyles.radiusLarge), + ), + ), + onChanged: (value) => provider.setSearchQuery(value), ), - onChanged: (value) => provider.setSearchQuery(value), ), - ), - ), - + ); + }), const SizedBox(width: 8), - // Settings button SizedBox( width: 44, height: 44, @@ -155,11 +181,10 @@ class MemoriesPageState extends State { borderRadius: BorderRadius.circular(12), ), ), - child: Icon(FontAwesomeIcons.gear, size: 16), + child: const Icon(FontAwesomeIcons.sliders, size: 16), ), ), const SizedBox(width: 8), - // Create button SizedBox( width: 44, height: 44, @@ -176,17 +201,61 @@ class MemoriesPageState extends State { borderRadius: BorderRadius.circular(12), ), ), - child: Icon(FontAwesomeIcons.plus, size: 18), + child: const Icon(FontAwesomeIcons.plus, size: 18), ), ), ], ), ), ), - - // Remove category filter section - - // Empty persistent header with zero height + if (provider.unreviewed.isNotEmpty) + SliverPersistentHeader( + pinned: true, + floating: true, + delegate: _ReviewPromptHeaderDelegate( + height: 56.0, + child: Material( + color: Theme.of(context).colorScheme.surfaceVariant, + elevation: 1, + child: InkWell( + onTap: () => _showReviewSheet(context, provider.unreviewed, provider), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Expanded( + child: Row( + children: [ + Icon(FontAwesomeIcons.listCheck, + color: Theme.of(context).colorScheme.onSurfaceVariant, size: 18), + const SizedBox(width: 12), + Flexible( + child: Text( + '${provider.unreviewed.length} ${provider.unreviewed.length == 1 ? "memory" : "memories"} to review', + style: TextStyle( + color: Theme.of(context).colorScheme.onSurfaceVariant, + fontWeight: FontWeight.w500), + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + ), + Padding( + padding: const EdgeInsets.only(left: 8.0), + child: Text('Review', + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold)), + ), + ], + ), + ), + ), + ), + ), + ), SliverPersistentHeader( pinned: true, floating: true, @@ -227,7 +296,7 @@ class MemoriesPageState extends State { ), ) : ListView.builder( - padding: const EdgeInsets.only(top: 8, left: 16, right: 16, bottom: 16), // Reduce top padding + padding: const EdgeInsets.only(top: 8, left: 16, right: 16, bottom: 16), itemCount: provider.filteredMemories.length, itemBuilder: (context, index) { final memory = provider.filteredMemories[index]; @@ -258,21 +327,23 @@ class MemoriesPageState extends State { ); } - void _showReviewSheet(List memories) async { - if (memories.isEmpty) return; + void _showReviewSheet(BuildContext context, List memories, MemoriesProvider existingProvider) async { + if (memories.isEmpty || !mounted) return; await showModalBottomSheet( context: context, backgroundColor: Colors.transparent, isDismissible: true, enableDrag: false, - builder: (context) => ListenableProvider( - create: (_) => MemoriesProvider(), - builder: (context, _) { - return MemoriesReviewSheet( - memories: memories, - provider: context.read(), - ); - }), + isScrollControlled: true, + builder: (sheetContext) { + return ChangeNotifierProvider.value( + value: existingProvider, + child: MemoriesReviewSheet( + memories: memories, + provider: existingProvider, + ), + ); + }, ); } diff --git a/app/lib/pages/memories/widgets/memory_review_sheet.dart b/app/lib/pages/memories/widgets/memory_review_sheet.dart index 955a3e2a8..083071d24 100644 --- a/app/lib/pages/memories/widgets/memory_review_sheet.dart +++ b/app/lib/pages/memories/widgets/memory_review_sheet.dart @@ -110,6 +110,7 @@ class MemoriesReviewSheet extends StatelessWidget { ), ], ), + const SizedBox(height: 10), ], ), ), From f693e944b6af18be01288368c61e67e98e9e2264 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 13:51:29 -0700 Subject: [PATCH 044/213] comment "i dont have omi" button --- .../pages/onboarding/device_selection.dart | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/app/lib/pages/onboarding/device_selection.dart b/app/lib/pages/onboarding/device_selection.dart index ce584a35e..d6645b3d4 100644 --- a/app/lib/pages/onboarding/device_selection.dart +++ b/app/lib/pages/onboarding/device_selection.dart @@ -109,22 +109,22 @@ class _DeviceSelectionPageState extends State with SingleTi const SizedBox( height: 24, ), - TextButton( - onPressed: () async { - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => const SocialHandleScreen()), - ); - }, - child: const Text( - 'I don\'t have omi', - style: TextStyle( - color: Colors.white, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), + // TextButton( + // onPressed: () async { + // Navigator.pushReplacement( + // context, + // MaterialPageRoute(builder: (context) => const SocialHandleScreen()), + // ); + // }, + // child: const Text( + // 'I don\'t have omi', + // style: TextStyle( + // color: Colors.white, + // fontWeight: FontWeight.bold, + // fontSize: 16, + // ), + // ), + // ), ], ), const Spacer(flex: 3), From cecff7f22c2549df0dafdc2e0c4236fe618d2f86 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 14:55:47 -0700 Subject: [PATCH 045/213] add mounted check for onPageFinished --- app/lib/pages/apps/app_home_web_page.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/lib/pages/apps/app_home_web_page.dart b/app/lib/pages/apps/app_home_web_page.dart index 77c67a747..c9f196150 100644 --- a/app/lib/pages/apps/app_home_web_page.dart +++ b/app/lib/pages/apps/app_home_web_page.dart @@ -45,9 +45,11 @@ class _AppHomeWebPageState extends State with SingleTickerProvid ..setNavigationDelegate( NavigationDelegate( onPageFinished: (String url) { - setState(() { - _isLoading = false; - }); + if (mounted) { + setState(() { + _isLoading = false; + }); + } }, onWebResourceError: (WebResourceError error) { setState(() { From 62d4904725add5fc60661a02a92d0f152bf3fdab Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 16:59:01 -0700 Subject: [PATCH 046/213] show app desc for popular apps instead of category --- app/lib/pages/apps/widgets/app_section_card.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/lib/pages/apps/widgets/app_section_card.dart b/app/lib/pages/apps/widgets/app_section_card.dart index c527ed9a7..7242f9ac6 100644 --- a/app/lib/pages/apps/widgets/app_section_card.dart +++ b/app/lib/pages/apps/widgets/app_section_card.dart @@ -7,6 +7,7 @@ import 'package:omi/pages/apps/app_detail/app_detail.dart'; import 'package:omi/providers/app_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; +import 'package:omi/widgets/extensions/string.dart'; import 'package:provider/provider.dart'; class AppSectionCard extends StatelessWidget { @@ -146,7 +147,7 @@ class SectionAppItemCard extends StatelessWidget { Padding( padding: const EdgeInsets.only(top: 2.0), child: Text( - app.getCategoryName(), + app.description.decodeString, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.grey, fontSize: 13), From c40c5b85feb814319b8708d7221c61c5612488e8 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 16:59:41 -0700 Subject: [PATCH 047/213] add further events for memories --- .../pages/memories/memories_review_page.dart | 4 +- app/lib/pages/memories/page.dart | 12 ++++- .../memories/widgets/memory_review_sheet.dart | 1 + app/lib/providers/memories_provider.dart | 40 ++++++++++++--- app/lib/utils/analytics/mixpanel.dart | 50 +++++++++++++++++++ 5 files changed, 97 insertions(+), 10 deletions(-) diff --git a/app/lib/pages/memories/memories_review_page.dart b/app/lib/pages/memories/memories_review_page.dart index 1ab970251..c9c5e246f 100644 --- a/app/lib/pages/memories/memories_review_page.dart +++ b/app/lib/pages/memories/memories_review_page.dart @@ -63,7 +63,7 @@ class _MemoriesReviewPageState extends State { // Process memories with a small delay to allow UI to update for (var memory in memoriesToProcess) { await Future.delayed(const Duration(milliseconds: 20)); - context.read().reviewMemory(memory, approve); + context.read().reviewMemory(memory, approve, 'review_page_batch'); } setState(() { @@ -104,7 +104,7 @@ class _MemoriesReviewPageState extends State { setState(() => _isProcessing = true); // Process the single memory - context.read().reviewMemory(memory, approve); + context.read().reviewMemory(memory, approve, 'review_page_single'); setState(() { remainingMemories.remove(memory); diff --git a/app/lib/pages/memories/page.dart b/app/lib/pages/memories/page.dart index f0702d3ca..0251e8dc5 100644 --- a/app/lib/pages/memories/page.dart +++ b/app/lib/pages/memories/page.dart @@ -145,6 +145,7 @@ class MemoriesPageState extends State with AutomaticKeepAliveClien onPressed: () { _searchController.clear(); provider.setSearchQuery(''); + MixpanelManager().memorySearchCleared(provider.memories.length); }, ) ] @@ -161,6 +162,11 @@ class MemoriesPageState extends State with AutomaticKeepAliveClien ), ), onChanged: (value) => provider.setSearchQuery(value), + onSubmitted: (value) { + if (value.isNotEmpty) { + MixpanelManager().memorySearched(value, provider.filteredMemories.length); + } + }, ), ), ); @@ -303,7 +309,10 @@ class MemoriesPageState extends State with AutomaticKeepAliveClien return MemoryItem( memory: memory, provider: provider, - onTap: _showQuickEditSheet, + onTap: (BuildContext context, Memory tappedMemory, MemoriesProvider tappedProvider) { + MixpanelManager().memoryListItemClicked(tappedMemory); + _showQuickEditSheet(context, tappedMemory, tappedProvider); + }, ); }, ), @@ -400,6 +409,7 @@ class MemoriesPageState extends State with AutomaticKeepAliveClien } void _showMemoryManagementSheet(BuildContext context, MemoriesProvider provider) { + MixpanelManager().memoriesManagementSheetOpened(); showModalBottomSheet( context: context, backgroundColor: Colors.transparent, diff --git a/app/lib/pages/memories/widgets/memory_review_sheet.dart b/app/lib/pages/memories/widgets/memory_review_sheet.dart index 083071d24..8b5a86d13 100644 --- a/app/lib/pages/memories/widgets/memory_review_sheet.dart +++ b/app/lib/pages/memories/widgets/memory_review_sheet.dart @@ -29,6 +29,7 @@ class MemoriesReviewSheet extends StatelessWidget { margin: const EdgeInsets.only(bottom: 12), child: Column( children: [ + const SizedBox(height: 10), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ diff --git a/app/lib/providers/memories_provider.dart b/app/lib/providers/memories_provider.dart index c7cecbef4..26c1eca4c 100644 --- a/app/lib/providers/memories_provider.dart +++ b/app/lib/providers/memories_provider.dart @@ -3,6 +3,7 @@ import 'package:omi/backend/http/api/memories.dart'; import 'package:omi/backend/preferences.dart'; import 'package:omi/backend/schema/memory.dart'; import 'package:omi/providers/base_provider.dart'; +import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:tuple/tuple.dart'; import 'package:uuid/uuid.dart'; import 'package:flutter/foundation.dart'; @@ -86,9 +87,13 @@ class MemoriesProvider extends ChangeNotifier { } void deleteAllMemories() async { + final int countBeforeDeletion = _memories.length; await deleteAllMemoriesServer(); _memories.clear(); _unreviewed.clear(); + if (countBeforeDeletion > 0) { + MixpanelManager().memoriesAllDeleted(countBeforeDeletion); + } _setCategories(); } @@ -117,9 +122,12 @@ class MemoriesProvider extends ChangeNotifier { final idx = _memories.indexWhere((m) => m.id == memory.id); if (idx != -1) { - memory.visibility = visibility; - _memories[idx] = memory; - _unreviewed.remove(memory); + Memory memoryToUpdate = _memories[idx]; + memoryToUpdate.visibility = visibility; + _memories[idx] = memoryToUpdate; + _unreviewed.removeWhere((m) => m.id == memory.id); + + MixpanelManager().memoryVisibilityChanged(memoryToUpdate, visibility); _setCategories(); } } @@ -147,7 +155,9 @@ class MemoriesProvider extends ChangeNotifier { } } - void reviewMemory(Memory memory, bool approved) async { + void reviewMemory(Memory memory, bool approved, String source) async { + MixpanelManager().memoryReviewed(memory, approved, source); + await reviewMemoryServer(memory.id, approved); final idx = _memories.indexWhere((m) => m.id == memory.id); @@ -176,13 +186,29 @@ class MemoriesProvider extends ChangeNotifier { Future updateAllMemoriesVisibility(bool makePrivate) async { final visibility = makePrivate ? MemoryVisibility.private : MemoryVisibility.public; + int updatedCount = 0; + List memoriesSuccessfullyUpdated = []; - for (var memory in _memories) { + for (var memory in List.from(_memories)) { if (memory.visibility != visibility) { - await updateMemoryVisibility(memory, visibility); + try { + await updateMemoryVisibilityServer(memory.id, visibility.name); + final idx = _memories.indexWhere((m) => m.id == memory.id); + if (idx != -1) { + _memories[idx].visibility = visibility; + memoriesSuccessfullyUpdated.add(_memories[idx]); + updatedCount++; + } + } catch (e) { + print('Failed to update visibility for memory ${memory.id}: $e'); + } } } - notifyListeners(); + if (updatedCount > 0) { + MixpanelManager().memoriesAllVisibilityChanged(visibility, updatedCount); + } + + _setCategories(); } } diff --git a/app/lib/utils/analytics/mixpanel.dart b/app/lib/utils/analytics/mixpanel.dart index aa176959e..2cf7137d3 100644 --- a/app/lib/utils/analytics/mixpanel.dart +++ b/app/lib/utils/analytics/mixpanel.dart @@ -167,6 +167,56 @@ class MixpanelManager { void memoriesPageCreatedMemory(MemoryCategory category) => track('Fact Page Created Fact', properties: {'fact_category': category.toString().split('.').last}); + void memorySearched(String query, int resultsCount) { + track('Fact Searched', properties: { + 'search_query_length': query.length, + 'results_count': resultsCount, + }); + } + + void memorySearchCleared(int totalFactsCount) { + track('Fact Search Cleared', properties: {'total_facts_count': totalFactsCount}); + } + + void memoryListItemClicked(Memory memory) { + track('Fact List Item Clicked', properties: { + 'fact_id': memory.id, + 'fact_category': memory.category.toString().split('.').last, + }); + } + + void memoryVisibilityChanged(Memory memory, MemoryVisibility newVisibility) { + track('Fact Visibility Changed', properties: { + 'fact_id': memory.id, + 'fact_category': memory.category.toString().split('.').last, + 'new_visibility': newVisibility.name, + }); + } + + void memoriesAllVisibilityChanged(MemoryVisibility newVisibility, int count) { + track('All Facts Visibility Changed', properties: { + 'new_visibility': newVisibility.name, + 'facts_count': count, + }); + } + + void memoryReviewed(Memory memory, bool approved, String source) { + track('Fact Reviewed', properties: { + 'fact_id': memory.id, + 'fact_category': memory.category.toString().split('.').last, + 'status': approved ? 'approved' : 'discarded', + 'source': source, + }); + } + + void memoriesAllDeleted(int countBeforeDeletion) { + track('All Facts Deleted', properties: { + 'facts_count_before_deletion': countBeforeDeletion, + }); + } + + void memoriesManagementSheetOpened() => track('Facts Management Sheet Opened'); + Map _getTranscriptProperties(String transcript) { String transcriptCopy = transcript.substring(0, transcript.length); int speakersCount = 0; From 05d8de90f2c1812e93f8fd33c589b6ccc7662b40 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 16:59:52 -0700 Subject: [PATCH 048/213] persona navigation fix --- .../pages/apps/widgets/create_options_sheet.dart | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/lib/pages/apps/widgets/create_options_sheet.dart b/app/lib/pages/apps/widgets/create_options_sheet.dart index 00141f6df..a65157b54 100644 --- a/app/lib/pages/apps/widgets/create_options_sheet.dart +++ b/app/lib/pages/apps/widgets/create_options_sheet.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:omi/pages/apps/add_app.dart'; +import 'package:omi/pages/persona/persona_profile.dart'; import 'package:omi/pages/persona/persona_provider.dart'; import 'package:omi/providers/home_provider.dart'; import 'package:provider/provider.dart'; @@ -64,8 +65,16 @@ class CreateOptionsSheet extends StatelessWidget { MixpanelManager().pageOpened('Create Persona'); // Set routing in provider and navigate to Persona Profile page Provider.of(context, listen: false).setRouting(PersonaProfileRouting.create_my_clone); - Provider.of(context, listen: false).setIndex(3); - Provider.of(context, listen: false).onSelectedIndexChanged!(3); + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PersonaProfilePage(), + settings: const RouteSettings( + arguments: 'from_settings', + ), + ), + ); + // Provider.of(context, listen: false).setIndex(3); + // Provider.of(context, listen: false).onSelectedIndexChanged!(3); }, ), ), From 1f58af0f4fd64f538d8c2e56852ee435b2ef7491 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 17:23:04 -0700 Subject: [PATCH 049/213] frontend deployment path and deps fix --- web/frontend/Dockerfile.datadog | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/frontend/Dockerfile.datadog b/web/frontend/Dockerfile.datadog index 5c4b34e90..e830f9e73 100644 --- a/web/frontend/Dockerfile.datadog +++ b/web/frontend/Dockerfile.datadog @@ -22,9 +22,11 @@ RUN \ FROM base AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules +COPY --from=deps /app/package.json ./package.json +COPY --from=deps /app/yarn.lock* /app/package-lock.json* /app/pnpm-lock.yaml* ./ #COPY frontend/. . ENV API_URL=https://backend-hhibjajaja-uc.a.run.app -COPY . . +COPY web/frontend/. ./ RUN npm run build RUN echo "base files" From cb1879010733779cc0396275f5f2e35c57f3a197 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 18:37:16 -0700 Subject: [PATCH 050/213] rearrange memories page --- app/lib/pages/home/page.dart | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index e168cf02b..30d5f68a9 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -183,16 +183,16 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker break; case "chat": homePageIdx = 1; - case "apps": + case "memoriesPage": homePageIdx = 2; break; - case "memoriesPage": + case "apps": homePageIdx = 3; break; } } - // Home controler + // Home controller _controller = PageController(initialPage: homePageIdx); context.read().selectedIndex = homePageIdx; context.read().onSelectedIndexChanged = (index) { @@ -378,8 +378,8 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker children: const [ ConversationsPage(), ChatPage(isPivotBottom: false), - AppsPage(), MemoriesPage(), + AppsPage(), ], ), ), @@ -415,7 +415,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker indicatorPadding: EdgeInsets.zero, onTap: (index) { MixpanelManager() - .bottomNavigationTabClicked(['Memories', 'Chat', 'Explore', 'Facts'][index]); + .bottomNavigationTabClicked(['Memories', 'Chat', 'Facts', 'Explore'][index]); primaryFocus?.unfocus(); if (home.selectedIndex == index) { return; @@ -471,13 +471,13 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker mainAxisSize: MainAxisSize.min, children: [ Icon( - FontAwesomeIcons.search, + FontAwesomeIcons.brain, color: home.selectedIndex == 2 ? Colors.white : Colors.grey, size: 18, ), const SizedBox(height: 6), Text( - 'Explore', + 'Memories', style: TextStyle( color: home.selectedIndex == 2 ? Colors.white : Colors.grey, fontSize: 12, @@ -491,13 +491,13 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker mainAxisSize: MainAxisSize.min, children: [ Icon( - FontAwesomeIcons.brain, + FontAwesomeIcons.search, color: home.selectedIndex == 3 ? Colors.white : Colors.grey, size: 18, ), const SizedBox(height: 6), Text( - 'Memories', + 'Explore', style: TextStyle( color: home.selectedIndex == 3 ? Colors.white : Colors.grey, fontSize: 12, @@ -564,7 +564,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return Center( child: Padding( padding: EdgeInsets.only(right: MediaQuery.sizeOf(context).width * 0.10), - child: const Text('Explore', + child: const Text('Memories', style: TextStyle( color: Colors.white, fontSize: 22, @@ -576,7 +576,7 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker return Center( child: Padding( padding: EdgeInsets.only(right: MediaQuery.sizeOf(context).width * 0.10), - child: const Text('Memories', + child: const Text('Explore', style: TextStyle( color: Colors.white, fontSize: 22, @@ -585,9 +585,9 @@ class _HomePageState extends State with WidgetsBindingObserver, Ticker ), ); } else { - return Expanded( + return const Expanded( child: Center( - child: const Text( + child: Text( '', style: TextStyle( color: Colors.white, From 5acc2c2cc7e14cc495ab02ad49a8618402cd263c Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 18:37:40 -0700 Subject: [PATCH 051/213] improve review sheet and remove memory category --- .../pages/memories/widgets/memory_item.dart | 52 +++++++------------ .../memories/widgets/memory_review_sheet.dart | 23 ++++---- 2 files changed, 33 insertions(+), 42 deletions(-) diff --git a/app/lib/pages/memories/widgets/memory_item.dart b/app/lib/pages/memories/widgets/memory_item.dart index 76fb371d4..fe396aba6 100644 --- a/app/lib/pages/memories/widgets/memory_item.dart +++ b/app/lib/pages/memories/widgets/memory_item.dart @@ -6,7 +6,6 @@ import 'package:omi/utils/ui_guidelines.dart'; import 'package:omi/widgets/extensions/string.dart'; import 'delete_confirmation.dart'; -import 'category_chip.dart'; class MemoryItem extends StatelessWidget { final Memory memory; @@ -28,36 +27,21 @@ class MemoryItem extends StatelessWidget { onTap: () => onTap(context, memory, provider), child: Container( margin: const EdgeInsets.only(bottom: AppStyles.spacingM), + padding: const EdgeInsets.symmetric(horizontal: AppStyles.spacingL, vertical: AppStyles.spacingL), decoration: AppStyles.cardDecoration, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Padding( - padding: const EdgeInsets.all(AppStyles.spacingL), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Expanded( - child: CategoryChip( - category: memory.category, - showIcon: true, - ), - ), - _buildVisibilityButton(context), - ], - ), - const SizedBox(height: AppStyles.spacingM), - Text( - memory.content.decodeString, - style: AppStyles.body, - ), - ], + Expanded( + child: Text( + memory.content.decodeString, + style: AppStyles.body, + maxLines: 3, + overflow: TextOverflow.ellipsis, ), ), + const SizedBox(width: AppStyles.spacingM), + _buildVisibilityButton(context), ], ), ), @@ -103,11 +87,11 @@ class MemoryItem extends StatelessWidget { ), offset: const Offset(0, 4), child: Container( - height: 26, - padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 0), + height: 36, + width: 56, decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), - borderRadius: BorderRadius.circular(AppStyles.radiusSmall), + borderRadius: BorderRadius.circular(AppStyles.radiusMedium), ), child: Row( mainAxisSize: MainAxisSize.min, @@ -118,10 +102,10 @@ class MemoryItem extends StatelessWidget { size: 16, color: Colors.white70, ), - const SizedBox(width: 4), + const SizedBox(width: 6), const Icon( Icons.keyboard_arrow_down, - size: 16, + size: 18, color: Colors.white70, ), ], @@ -143,6 +127,7 @@ class MemoryItem extends StatelessWidget { ], onSelected: (visibility) { provider.updateMemoryVisibility(memory, visibility); + MixpanelManager().memoryVisibilityChanged(memory, visibility); }, ); } @@ -178,13 +163,14 @@ class MemoryItem extends StatelessWidget { fontWeight: isSelected ? FontWeight.w600 : FontWeight.normal, ), ), - const SizedBox(height: 2), Text( description, style: TextStyle( color: Colors.grey.shade400, fontSize: 12, ), + maxLines: 2, + overflow: TextOverflow.ellipsis, ), ], ), diff --git a/app/lib/pages/memories/widgets/memory_review_sheet.dart b/app/lib/pages/memories/widgets/memory_review_sheet.dart index 8b5a86d13..b91c94645 100644 --- a/app/lib/pages/memories/widgets/memory_review_sheet.dart +++ b/app/lib/pages/memories/widgets/memory_review_sheet.dart @@ -70,9 +70,17 @@ class MemoriesReviewSheet extends StatelessWidget { borderRadius: BorderRadius.circular(10), ), ), - onPressed: () => Navigator.pop(context), + onPressed: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => MemoriesReviewPage(memories: memories), + ), + ); + }, child: Text( - 'Later', + 'Review Manually', style: TextStyle( color: Colors.grey.shade300, fontSize: 14, @@ -91,16 +99,13 @@ class MemoriesReviewSheet extends StatelessWidget { ), ), onPressed: () { + for (var memory in memories) { + provider.reviewMemory(memory, true, 'review_sheet_accept_all'); + } Navigator.pop(context); - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => MemoriesReviewPage(memories: memories), - ), - ); }, child: const Text( - 'Review now', + 'Accept All', style: TextStyle( color: Colors.black, fontSize: 14, From 5a7ef8eed081b57e2b93f4eb6d5b0dcfb13ac3c2 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Wed, 14 May 2025 18:38:00 -0700 Subject: [PATCH 052/213] move persona to profile in settings --- app/lib/pages/settings/page.dart | 23 -------------- app/lib/pages/settings/profile.dart | 47 +++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/app/lib/pages/settings/page.dart b/app/lib/pages/settings/page.dart index a93ef3319..e3fde2a00 100644 --- a/app/lib/pages/settings/page.dart +++ b/app/lib/pages/settings/page.dart @@ -3,7 +3,6 @@ import 'package:omi/backend/auth.dart'; import 'package:omi/backend/preferences.dart'; import 'package:omi/main.dart'; import 'package:omi/pages/persona/persona_provider.dart'; -import 'package:omi/pages/persona/persona_profile.dart'; import 'package:omi/pages/settings/about.dart'; import 'package:omi/pages/settings/developer.dart'; import 'package:omi/pages/settings/profile.dart'; @@ -13,8 +12,6 @@ import 'package:omi/widgets/dialog.dart'; import 'package:intercom_flutter/intercom_flutter.dart'; import 'package:package_info_plus/package_info_plus.dart'; import 'package:provider/provider.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:omi/gen/assets.gen.dart'; import 'device_settings.dart'; @@ -71,26 +68,6 @@ class _SettingsPageState extends State { ), const SizedBox(height: 12), - getItemAddOn2( - 'Persona', - () { - Navigator.of(context).push( - MaterialPageRoute( - builder: (context) => const PersonaProfilePage(), - settings: const RouteSettings( - arguments: 'from_settings', - ), - ), - ); - }, - icon: SvgPicture.asset( - Assets.images.icPersonaProfile.path, - width: 24, - height: 24, - ), - ), - const SizedBox(height: 12), - // Device Settings getItemAddOn2( 'Device Settings', diff --git a/app/lib/pages/settings/profile.dart b/app/lib/pages/settings/profile.dart index 2f31a83bd..e54af1013 100644 --- a/app/lib/pages/settings/profile.dart +++ b/app/lib/pages/settings/profile.dart @@ -1,7 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:omi/backend/preferences.dart'; -import 'package:omi/pages/memories/page.dart'; import 'package:omi/pages/payments/payments_page.dart'; import 'package:omi/pages/settings/change_name_widget.dart'; import 'package:omi/pages/settings/language_selection_dialog.dart'; @@ -12,6 +11,9 @@ import 'package:omi/providers/home_provider.dart'; import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:provider/provider.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:omi/gen/assets.gen.dart'; +import 'package:omi/pages/persona/persona_profile.dart'; import 'delete_account.dart'; @@ -49,7 +51,7 @@ class _ProfilePageState extends State { Widget _buildProfileTile({ required String title, required String subtitle, - required IconData icon, + required Widget iconWidget, required VoidCallback onTap, Color iconColor = Colors.white, }) { @@ -77,7 +79,7 @@ class _ProfilePageState extends State { fontSize: 13, ), ), - trailing: Icon(icon, size: 20, color: iconColor), + trailing: iconWidget, onTap: onTap, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), @@ -168,7 +170,7 @@ class _ProfilePageState extends State { _buildProfileTile( title: SharedPreferencesUtil().givenName.isEmpty ? 'Set Your Name' : 'Change Your Name', subtitle: SharedPreferencesUtil().givenName.isEmpty ? 'Not set' : SharedPreferencesUtil().givenName, - icon: Icons.person, + iconWidget: const Icon(Icons.person, size: 20, color: Colors.white), onTap: () async { MixpanelManager().pageOpened('Profile Change Name'); await showDialog( @@ -192,7 +194,7 @@ class _ProfilePageState extends State { return _buildProfileTile( title: 'Primary Language', subtitle: languageName, - icon: Icons.language, + iconWidget: const Icon(Icons.language, size: 20, color: Colors.white), onTap: () async { MixpanelManager().pageOpened('Profile Change Language'); await LanguageSelectionDialog.show(context, isRequired: false, forceShow: true); @@ -202,13 +204,34 @@ class _ProfilePageState extends State { ); }, ), + _buildProfileTile( + title: 'Persona', + subtitle: 'Manage your Omi persona', + iconWidget: SvgPicture.asset( + Assets.images.icPersonaProfile.path, + width: 20, + height: 20, + colorFilter: const ColorFilter.mode(Colors.white, BlendMode.srcIn), + ), + onTap: () { + Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => const PersonaProfilePage(), + settings: const RouteSettings( + arguments: 'from_settings', + ), + ), + ); + MixpanelManager().pageOpened('Profile Persona Settings'); + }, + ), // VOICE & PEOPLE SECTION _buildSectionHeader('VOICE & PEOPLE'), _buildProfileTile( title: 'Speech Profile', subtitle: 'Teach Omi your voice', - icon: Icons.multitrack_audio, + iconWidget: const Icon(Icons.multitrack_audio, size: 20, color: Colors.white), onTap: () { routeToPage(context, const SpeechProfilePage()); MixpanelManager().pageOpened('Profile Speech Profile'); @@ -217,7 +240,7 @@ class _ProfilePageState extends State { _buildProfileTile( title: 'Identifying Others', subtitle: 'Tell Omi who said it 🗣️', - icon: Icons.people, + iconWidget: const Icon(Icons.people, size: 20, color: Colors.white), onTap: () { routeToPage(context, const UserPeoplePage()); }, @@ -228,7 +251,7 @@ class _ProfilePageState extends State { _buildProfileTile( title: 'Payment Methods', subtitle: 'Add or change your payment method', - icon: Icons.attach_money_outlined, + iconWidget: const Icon(Icons.attach_money_outlined, size: 20, color: Colors.white), onTap: () { routeToPage(context, const PaymentsPage()); }, @@ -256,17 +279,17 @@ class _ProfilePageState extends State { _buildProfileTile( title: 'User ID', subtitle: SharedPreferencesUtil().uid, - icon: Icons.copy_rounded, + iconWidget: const Icon(Icons.copy_rounded, size: 20, color: Colors.white), onTap: () { Clipboard.setData(ClipboardData(text: SharedPreferencesUtil().uid)); - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('User ID copied to clipboard'))); + ScaffoldMessenger.of(context) + .showSnackBar(const SnackBar(content: Text('User ID copied to clipboard'))); }, ), _buildProfileTile( title: 'Delete Account', subtitle: 'Delete your account and all data', - icon: Icons.warning, - iconColor: Colors.red.shade300, + iconWidget: Icon(Icons.warning, size: 20, color: Colors.red.shade300), onTap: () { MixpanelManager().pageOpened('Profile Delete Account Dialog'); Navigator.push(context, MaterialPageRoute(builder: (context) => const DeleteAccount())); From bc44a0713c41c6e2aed7ec8c1798a080e75489e9 Mon Sep 17 00:00:00 2001 From: Joan Cabezas Date: Wed, 14 May 2025 19:10:32 -0700 Subject: [PATCH 053/213] initial omi agent replacement, consuming mcp --- backend/utils/agent.py | 108 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 backend/utils/agent.py diff --git a/backend/utils/agent.py b/backend/utils/agent.py new file mode 100644 index 000000000..aa40a9fa7 --- /dev/null +++ b/backend/utils/agent.py @@ -0,0 +1,108 @@ +import asyncio +from typing import AsyncGenerator, List, Optional +from agents import Agent, ModelSettings, Runner +from dotenv import load_dotenv +from agents import Agent, Runner, trace +from agents.mcp import MCPServer, MCPServerStdio +from agents.model_settings import Reasoning + +from models.chat import Message, ChatSession +from utils.retrieval.graph import AsyncStreamingCallback +from openai.types.responses import ResponseTextDeltaEvent + + +load_dotenv() + +# omi_documentation: dict = get_github_docs_content() +# omi_documentation_str = "\n\n".join( +# [f"{k}:\n {v}" for k, v in omi_documentation.items()] +# ) +omi_documentation_str = "" +omi_documentation_prompt = f""" +You are a helpful assistant that answers questions from the Omi documentation. + +Documentation: +{omi_documentation_str} +""" + + +async def run( + mcp_server: MCPServer, + uid: str, + message: str, + respond: callable, + stream_callback: Optional[AsyncStreamingCallback] = None, +): + docs_agent = Agent( + name="Omi Documentation Agent", + instructions=omi_documentation_prompt, + model="o4-mini", + ) + omi_agent = Agent( + name="Omi Agent", + instructions=f"You are a helpful assistant that answers questions from the user {uid}, using the tools you were provided.", + mcp_servers=[mcp_server], + model="o4-mini", + model_settings=ModelSettings( + reasoning=Reasoning(effort="high"), # summary="auto" + ), + tools=[ + docs_agent.as_tool( + tool_name="docs_agent", + tool_description="Answer user questions from the Omi documentation.", + ) + ], + ) + + print("\n" + "-" * 40) + print(f"Running: {message}") + result = Runner.run_streamed(starting_agent=omi_agent, input=message) + respond(result.final_output) + + async for event in result.stream_events(): + if event.type == "raw_response_event" and isinstance( + event.data, ResponseTextDeltaEvent + ): + print(event.data.delta, end="", flush=True) + if stream_callback: + await stream_callback.put_data(event.data.delta) + + +async def execute(): + async with MCPServerStdio( + cache_tools_list=True, + params={"command": "uvx", "args": ["mcp-server-omi"]}, + ) as server: + with trace(workflow_name="Omi Agent"): + await run( + server, + "viUv7GtdoHXbK1UBCDlPuTDuPgJ2", + "What do you know about me?", + lambda x: print(x), + ) + + +if __name__ == "__main__": + + async def interactive_chat(): + print("Starting interactive chat with Omi Agent. Type 'exit' to quit.") + async with MCPServerStdio( + cache_tools_list=True, + params={"command": "uvx", "args": ["mcp-server-omi", "-v"]}, + ) as server: + while True: + user_input = input("\nYou: ") + if user_input.lower() == "exit": + break + + print("\nOmi: ", end="", flush=True) + + with trace(workflow_name="Omi Agent"): + await run( + server, + "viUv7GtdoHXbK1UBCDlPuTDuPgJ2", + user_input, + lambda x: None, # Response is streamed in real-time + ) + + asyncio.run(interactive_chat()) From 63c317dfada539b68879d947bc17cfb6206191ad Mon Sep 17 00:00:00 2001 From: Joan Cabezas Date: Thu, 15 May 2025 02:32:00 -0700 Subject: [PATCH 054/213] example agents sdk set's model + reasoning effort --- mcp/examples/app.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mcp/examples/app.py b/mcp/examples/app.py index 6ee660dee..ace78d0f0 100644 --- a/mcp/examples/app.py +++ b/mcp/examples/app.py @@ -3,8 +3,9 @@ import shutil from dotenv import load_dotenv -from agents import Agent, Runner, trace +from agents import Agent, Runner, trace, ModelSettings from agents.mcp import MCPServerStdio +from openai.types.shared import Reasoning load_dotenv() @@ -82,10 +83,12 @@ async def process_message_with_agent( name="Omi Agent", instructions=f"You are a helpful assistant that answers questions based on my Omi data, my UID is {uid}. You are processing a conversation, the history of which is provided.", mcp_servers=[server], - model="o4-mini", + model="o3", + # model="litellm/anthropic/claude-3-7-sonnet-20250219", + model_settings=ModelSettings(reasoning=Reasoning(effort="high")), ) - with trace(workflow_name="Streamlit_Omi_Agent_Chat_Interaction"): + with trace(workflow_name="Stramlit Omi MCP Example"): run_output = await Runner.run( starting_agent=omi_agent, input=agent_input_messages, # Pass the formatted conversation history From b0ec6154a90bd7905b0a55a157d26708e7520723 Mon Sep 17 00:00:00 2001 From: Joan Cabezas Date: Thu, 15 May 2025 02:47:18 -0700 Subject: [PATCH 055/213] mcp limits/offset params, memory categories fix, description schema improved --- mcp/src/mcp_server_omi/server.py | 80 ++++++++++++++++++++++++-------- 1 file changed, 60 insertions(+), 20 deletions(-) diff --git a/mcp/src/mcp_server_omi/server.py b/mcp/src/mcp_server_omi/server.py index 4594964a4..39ac92967 100644 --- a/mcp/src/mcp_server_omi/server.py +++ b/mcp/src/mcp_server_omi/server.py @@ -58,8 +58,8 @@ class ConversationCategory(str, Enum): other = "other" -base_url = "https://backend-208440318997.us-central1.run.app/v1/mcp/" -# base_url = "http://127.0.0.1:8000/v1/mcp/" +# base_url = "https://backend-208440318997.us-central1.run.app/v1/mcp/" +base_url = "http://127.0.0.1:8000/v1/mcp/" class OmiTools(str, Enum): @@ -83,6 +83,8 @@ class GetMemories(BaseModel): categories: List[MemoryCategory] = Field( description="The categories of memories to filter by.", default=[] ) + limit: int = Field(description="The number of memories to retrieve.", default=100) + offset: int = Field(description="The offset of the memories to retrieve.", default=0) class CreateMemory(BaseModel): @@ -106,15 +108,17 @@ class EditMemory(BaseModel): class GetConversations(BaseModel): uid: str = Field(description="The user's unique identifier.") - start_date: Optional[datetime] = Field( - description="Filter conversations after this date", default=None + start_date: Optional[str] = Field( + description="Filter conversations after this date (yyyy-mm-dd)", default=None ) - end_date: Optional[datetime] = Field( - description="Filter conversations before this date", default=None + end_date: Optional[str] = Field( + description="Filter conversations before this date (yyyy-mm-dd)", default=None ) categories: List[ConversationCategory] = Field( description="Filter by conversation categories.", default=[] ) + limit: int = Field(description="The number of conversations to retrieve.", default=20) + offset: int = Field(description="The offset of the conversations to retrieve.", default=0) class GetConversationById(BaseModel): @@ -131,15 +135,24 @@ def create_user(email: str, password: str, name: str) -> dict: def get_memories( + logger: logging.Logger, uid: str, + offset: int = 0, limit: int = 100, categories: List[MemoryCategory] = [], ) -> List: - params = {"limit": limit} + logger.info(f"Getting memories with params: {offset}, {limit}, {categories}") + params = {"offset": offset, "limit": limit} if categories: - params["categories"] = ",".join(categories) - response = requests.get(f"{base_url}memories", params=params, headers={"uid": uid}) - return response.json() + params["categories"] = ",".join([c.value for c in categories]) + logger.info(f"get_memories params: {params}") + try: + response = requests.get(f"{base_url}memories", params=params, headers={"uid": uid}) + logger.info(f"get_memories response: {response.json()}") + return response.json() + except Exception as e: + logger.error(f"Error getting memories: {e}") + raise e def create_memory(uid: str, content: str, category: MemoryCategory) -> dict: @@ -168,15 +181,23 @@ def edit_memory(uid: str, memory_id: str, content: str) -> dict: def get_conversations( logger: logging.Logger, uid: str, - start_date: Optional[datetime] = None, - end_date: Optional[datetime] = None, + start_date: Optional[str] = None, + end_date: Optional[str] = None, categories: List[ConversationCategory] = [], + limit: int = 20, + offset: int = 0, ) -> List: - params = {"limit": 10, "offset": 0} + params = {"limit": limit, "offset": offset} if start_date: - params["start_date"] = start_date.isoformat() + try: + params["start_date"] = datetime.strptime(start_date, "%Y-%m-%d").isoformat() + except ValueError: + logger.warning(f"Could not parse start date: {start_date}") if end_date: - params["end_date"] = end_date.isoformat() + try: + params["end_date"] = datetime.strptime(end_date, "%Y-%m-%d").isoformat() + except ValueError: + logger.warning(f"Could not parse end date: {end_date}") if categories: params["categories"] = ",".join(categories) @@ -212,22 +233,22 @@ async def list_tools() -> list[Tool]: ), Tool( name=OmiTools.GET_MEMORIES, - description="Retrieve memories. A memory is a known fact about the user across multiple domains.", + description="Retrieve a list of memories. A memory is a known fact about the user across multiple domains.", inputSchema=GetMemories.model_json_schema(), ), Tool( name=OmiTools.CREATE_MEMORY, - description="Create a new memory", + description="Create a new memory. A memory is a known fact about the user across multiple domains.", inputSchema=CreateMemory.model_json_schema(), ), Tool( name=OmiTools.DELETE_MEMORY, - description="Delete a memory by ID", + description="Delete a memory by ID. A memory is a known fact about the user across multiple domains.", inputSchema=DeleteMemory.model_json_schema(), ), Tool( name=OmiTools.EDIT_MEMORY, - description="Edit a memory's content", + description="Edit a memory's content. A memory is a known fact about the user across multiple domains.", inputSchema=EditMemory.model_json_schema(), ), Tool( @@ -259,10 +280,23 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]: # raise ValueError(f"uid is required {arguments}") _uid = arguments["uid"] if name == OmiTools.GET_MEMORIES: + # return [TextContent(type="text", text=json.dumps(arguments, indent=2))] + categories: List[str] = arguments.get("categories", []) + if not isinstance(categories, list): + raise ValueError(f"categories must be a list, got {type(categories)}") + categories_enum = [] + for category in categories: + try: + categories_enum.append(MemoryCategory(category)) + except ValueError: + logger.warning(f"Could not parse category: {category}") + result = get_memories( + logger, _uid, + offset=arguments.get("offset", 0), limit=arguments.get("limit", 100), - categories=arguments.get("categories", []), + categories=categories_enum, ) return [TextContent(type="text", text=json.dumps(result, indent=2))] @@ -294,6 +328,8 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]: start_date=arguments.get("start_date"), end_date=arguments.get("end_date"), categories=arguments.get("categories", []), + limit=arguments.get("limit", 20), + offset=arguments.get("offset", 0), ) return [TextContent(type="text", text=json.dumps(result, indent=2))] @@ -308,3 +344,7 @@ async def call_tool(name: str, arguments: dict) -> list[TextContent]: options = server.create_initialization_options() async with stdio_server() as (read_stream, write_stream): await server.run(read_stream, write_stream, options, raise_exceptions=True) + + +# TODO: +# - add get conversations by semantic search + reranking \ No newline at end of file From 89f9cb90dc45a5fa9ce71d9399ee54bcd6b1b49d Mon Sep 17 00:00:00 2001 From: Joan Cabezas Date: Thu, 15 May 2025 02:58:34 -0700 Subject: [PATCH 056/213] minor changes mcp + example --- mcp/examples/openai_agents_sdk_ex.py | 10 ++++++++-- mcp/src/mcp_server_omi/__about__.py | 2 +- mcp/src/mcp_server_omi/server.py | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/mcp/examples/openai_agents_sdk_ex.py b/mcp/examples/openai_agents_sdk_ex.py index fd5299191..adfa8b2d2 100644 --- a/mcp/examples/openai_agents_sdk_ex.py +++ b/mcp/examples/openai_agents_sdk_ex.py @@ -1,10 +1,10 @@ import os -from agents import Agent, Runner +from agents import Agent, ModelSettings, Runner, trace from dotenv import load_dotenv import asyncio import shutil +from openai.types.shared import Reasoning -from agents import Agent, Runner, trace from agents.mcp import MCPServer, MCPServerStdio @@ -23,6 +23,12 @@ async def run(mcp_server: MCPServer): instructions=f"You are a helpful assistant that answers questions based on the user's OMI data, the user UID is {uid}.", mcp_servers=[mcp_server], model="o4-mini", + model_settings=ModelSettings( + reasoning=Reasoning( + effort="high", + generate_summary="auto", + ) + ), ) message = "Check my memories, and get an overall idea of who I am, then retrieve my 5 most recent conversations and summarize them." diff --git a/mcp/src/mcp_server_omi/__about__.py b/mcp/src/mcp_server_omi/__about__.py index e4a036dac..ec57f7508 100644 --- a/mcp/src/mcp_server_omi/__about__.py +++ b/mcp/src/mcp_server_omi/__about__.py @@ -1 +1 @@ -__version__ = "0.1.3" \ No newline at end of file +__version__ = "0.1.5" \ No newline at end of file diff --git a/mcp/src/mcp_server_omi/server.py b/mcp/src/mcp_server_omi/server.py index 39ac92967..c67c641a1 100644 --- a/mcp/src/mcp_server_omi/server.py +++ b/mcp/src/mcp_server_omi/server.py @@ -58,8 +58,8 @@ class ConversationCategory(str, Enum): other = "other" -# base_url = "https://backend-208440318997.us-central1.run.app/v1/mcp/" -base_url = "http://127.0.0.1:8000/v1/mcp/" +base_url = "https://backend-208440318997.us-central1.run.app/v1/mcp/" +# base_url = "http://127.0.0.1:8000/v1/mcp/" class OmiTools(str, Enum): From 56b10ea5ecb97e0915edf097718ad44ea010b6df Mon Sep 17 00:00:00 2001 From: Joan Cabezas Date: Thu, 15 May 2025 10:25:53 -0700 Subject: [PATCH 057/213] execute_agent_chat_stream --- backend/utils/agent.py | 126 ++++++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 27 deletions(-) diff --git a/backend/utils/agent.py b/backend/utils/agent.py index aa40a9fa7..5560f7585 100644 --- a/backend/utils/agent.py +++ b/backend/utils/agent.py @@ -1,12 +1,13 @@ import asyncio -from typing import AsyncGenerator, List, Optional +from datetime import datetime, timezone +from typing import AsyncGenerator, List, Optional, Dict, Any, Tuple from agents import Agent, ModelSettings, Runner from dotenv import load_dotenv from agents import Agent, Runner, trace from agents.mcp import MCPServer, MCPServerStdio from agents.model_settings import Reasoning -from models.chat import Message, ChatSession +from models.chat import Message, ChatSession, MessageType from utils.retrieval.graph import AsyncStreamingCallback from openai.types.responses import ResponseTextDeltaEvent @@ -54,8 +55,6 @@ async def run( ], ) - print("\n" + "-" * 40) - print(f"Running: {message}") result = Runner.run_streamed(starting_agent=omi_agent, input=message) respond(result.final_output) @@ -63,12 +62,67 @@ async def run( if event.type == "raw_response_event" and isinstance( event.data, ResponseTextDeltaEvent ): - print(event.data.delta, end="", flush=True) if stream_callback: - await stream_callback.put_data(event.data.delta) + # Remove "data: " prefix if present + delta = event.data.delta + if isinstance(delta, str) and delta.startswith("data: "): + delta = delta[len("data: "):] + await stream_callback.put_data(delta) -async def execute(): +async def execute_agent_chat_stream( + uid: str, + messages: List[Message], + plugin: Optional[Any] = None, + cited: Optional[bool] = False, + callback_data: dict = {}, + chat_session: Optional[ChatSession] = None, +) -> AsyncGenerator[str, None]: + print("execute_agent_chat_stream plugin: ", plugin.id if plugin else "") + callback = AsyncStreamingCallback() + + async with MCPServerStdio( + cache_tools_list=True, + params={"command": "uvx", "args": ["mcp-server-omi", "-v"]}, + ) as server: + # TODO: include the whole messages list + last_message = messages[-1].text if messages else "" + + # Create a task to run the agent + task = asyncio.create_task( + run( + server, + uid, + last_message, + lambda x: callback_data.update({"answer": x}), + callback, + ) + ) + + # Stream the response chunks + while True: + try: + chunk = await callback.queue.get() + if chunk: + # Remove "data: " prefix if present + if isinstance(chunk, str) and chunk.startswith("data: "): + chunk = chunk[len("data: "):] + yield chunk + else: + break + except asyncio.CancelledError: + break + + await task + callback_data["memories_found"] = [] # No memories in this implementation + callback_data["ask_for_nps"] = False # No NPS in this implementation + callback_data["answer"] = "".join([]) # full_response + + yield None + return + + +async def send_single_message(): async with MCPServerStdio( cache_tools_list=True, params={"command": "uvx", "args": ["mcp-server-omi"]}, @@ -82,27 +136,45 @@ async def execute(): ) -if __name__ == "__main__": +async def interactive_chat_stream(): + print("Starting interactive chat with Omi Agent. Type 'exit' to quit.") + async with MCPServerStdio( + cache_tools_list=True, + params={"command": "uvx", "args": ["mcp-server-omi", "-v"]}, + ) as server: + while True: + user_input = input("\nYou: ") + if user_input.lower() == "exit": + break - async def interactive_chat(): - print("Starting interactive chat with Omi Agent. Type 'exit' to quit.") - async with MCPServerStdio( - cache_tools_list=True, - params={"command": "uvx", "args": ["mcp-server-omi", "-v"]}, - ) as server: - while True: - user_input = input("\nYou: ") - if user_input.lower() == "exit": - break + print("\nOmi: ", end="", flush=True) + + with trace(workflow_name="Omi Agent"): + await run( + server, + "viUv7GtdoHXbK1UBCDlPuTDuPgJ2", + user_input, + lambda x: None, # Response is streamed in real-time + ) - print("\nOmi: ", end="", flush=True) - with trace(workflow_name="Omi Agent"): - await run( - server, - "viUv7GtdoHXbK1UBCDlPuTDuPgJ2", - user_input, - lambda x: None, # Response is streamed in real-time - ) +if __name__ == "__main__": + + async def main(): + async for chunk in execute_agent_chat_stream( + uid="viUv7GtdoHXbK1UBCDlPuTDuPgJ2", + messages=[ + Message( + id="0", + sender="human", + type=MessageType.text, + text="Who was Napoleon?", + created_at=datetime.now(timezone.utc), + ) + ], + ): + if chunk: + print(chunk, end="", flush=True) + print() # for newline after stream ends - asyncio.run(interactive_chat()) + asyncio.run(main()) From a77c8607c1321cba78411636207d1c56539fda13 Mon Sep 17 00:00:00 2001 From: Joan Cabezas Date: Thu, 15 May 2025 10:44:29 -0700 Subject: [PATCH 058/213] agent handle multi message conversation --- backend/utils/agent.py | 79 ++++++++---- backend/utils/retrieval/graph_realtime.py | 140 ---------------------- 2 files changed, 53 insertions(+), 166 deletions(-) delete mode 100644 backend/utils/retrieval/graph_realtime.py diff --git a/backend/utils/agent.py b/backend/utils/agent.py index 5560f7585..0f9da5acd 100644 --- a/backend/utils/agent.py +++ b/backend/utils/agent.py @@ -1,19 +1,16 @@ import asyncio from datetime import datetime, timezone -from typing import AsyncGenerator, List, Optional, Dict, Any, Tuple -from agents import Agent, ModelSettings, Runner -from dotenv import load_dotenv -from agents import Agent, Runner, trace +from typing import AsyncGenerator, List, Optional, Any +from agents import Agent, ModelSettings, Runner, trace from agents.mcp import MCPServer, MCPServerStdio from agents.model_settings import Reasoning +from models.app import App from models.chat import Message, ChatSession, MessageType from utils.retrieval.graph import AsyncStreamingCallback from openai.types.responses import ResponseTextDeltaEvent -load_dotenv() - # omi_documentation: dict = get_github_docs_content() # omi_documentation_str = "\n\n".join( # [f"{k}:\n {v}" for k, v in omi_documentation.items()] @@ -30,8 +27,9 @@ async def run( mcp_server: MCPServer, uid: str, - message: str, + messages: List[Message], respond: callable, + plugin: Optional[App] = None, stream_callback: Optional[AsyncStreamingCallback] = None, ): docs_agent = Agent( @@ -55,7 +53,11 @@ async def run( ], ) - result = Runner.run_streamed(starting_agent=omi_agent, input=message) + messages = [ + {"role": "assistant" if m.sender.value == "ai" else "user", "content": m.text} + for m in messages + ] + result = Runner.run_streamed(starting_agent=omi_agent, input=messages) respond(result.final_output) async for event in result.stream_events(): @@ -66,14 +68,14 @@ async def run( # Remove "data: " prefix if present delta = event.data.delta if isinstance(delta, str) and delta.startswith("data: "): - delta = delta[len("data: "):] + delta = delta[len("data: ") :] await stream_callback.put_data(delta) async def execute_agent_chat_stream( uid: str, messages: List[Message], - plugin: Optional[Any] = None, + plugin: Optional[App] = None, cited: Optional[bool] = False, callback_data: dict = {}, chat_session: Optional[ChatSession] = None, @@ -85,16 +87,13 @@ async def execute_agent_chat_stream( cache_tools_list=True, params={"command": "uvx", "args": ["mcp-server-omi", "-v"]}, ) as server: - # TODO: include the whole messages list - last_message = messages[-1].text if messages else "" - - # Create a task to run the agent task = asyncio.create_task( run( server, uid, - last_message, + messages, lambda x: callback_data.update({"answer": x}), + plugin, callback, ) ) @@ -106,7 +105,7 @@ async def execute_agent_chat_stream( if chunk: # Remove "data: " prefix if present if isinstance(chunk, str) and chunk.startswith("data: "): - chunk = chunk[len("data: "):] + chunk = chunk[len("data: ") :] yield chunk else: break @@ -159,19 +158,47 @@ async def interactive_chat_stream(): if __name__ == "__main__": + messages = [ + Message( + id="0", + sender="human", + type=MessageType.text, + text="Who was Napoleon?", + created_at=datetime.now(timezone.utc), + ), + Message( + id="1", + sender="ai", + type=MessageType.text, + text="Napoleon Bonaparte was a French military leader and emperor who rose to prominence during the French Revolution and led several successful campaigns during the Revolutionary Wars. He became Emperor of the French from 1804 until 1814, and again in 1815 during the Hundred Days.", + created_at=datetime.now(timezone.utc), + ), + Message( + id="2", + sender="human", + type=MessageType.text, + text="What were some of his most significant achievements?", + created_at=datetime.now(timezone.utc), + ), + Message( + id="3", + sender="ai", + type=MessageType.text, + text="Some of Napoleon's most significant achievements include the Napoleonic Code, which influenced legal systems worldwide, his military reforms, and his role in spreading revolutionary ideals across Europe. He also reorganized the French education system and centralized the administrative structure of France.", + created_at=datetime.now(timezone.utc), + ), + Message( + id="4", + sender="human", + type=MessageType.text, + text="How did his reforms impact Europe after his defeat?", + created_at=datetime.now(timezone.utc), + ), + ] async def main(): async for chunk in execute_agent_chat_stream( - uid="viUv7GtdoHXbK1UBCDlPuTDuPgJ2", - messages=[ - Message( - id="0", - sender="human", - type=MessageType.text, - text="Who was Napoleon?", - created_at=datetime.now(timezone.utc), - ) - ], + uid="viUv7GtdoHXbK1UBCDlPuTDuPgJ2", messages=messages ): if chunk: print(chunk, end="", flush=True) diff --git a/backend/utils/retrieval/graph_realtime.py b/backend/utils/retrieval/graph_realtime.py deleted file mode 100644 index 74271b29b..000000000 --- a/backend/utils/retrieval/graph_realtime.py +++ /dev/null @@ -1,140 +0,0 @@ -import datetime -import os -import uuid -from typing import List, Optional, Tuple - -from langchain_openai import ChatOpenAI -from langgraph.checkpoint.memory import MemorySaver -from langgraph.constants import END -from langgraph.graph import START, StateGraph -from typing_extensions import TypedDict - -from models.transcript_segment import TranscriptSegment -from utils.other.endpoints import timeit - -# os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = '../../' + os.getenv('GOOGLE_APPLICATION_CREDENTIALS') - -import database.conversations as conversations_db -from database.redis_db import get_filter_category_items -from database.vector_db import query_vectors_by_metadata -from models.chat import Message -from models.conversation import Conversation -from utils.llm import select_structured_filters, generate_embedding, extract_question_from_transcript, \ - provide_advice_message - -model = ChatOpenAI(model='gpt-4o-mini') - - -class StructuredFilters(TypedDict): - topics: List[str] - people: List[str] - entities: List[str] - dates: List[datetime.date] - - -class GraphState(TypedDict): - uid: str - segments: List[TranscriptSegment] - parsed_question: Optional[str] - - filters: Optional[StructuredFilters] - - memories_found: Optional[List[Conversation]] - - answer: Optional[str] - - -def extract_question(state: GraphState): - question = extract_question_from_transcript(state.get('uid'), state.get('segments', [])) - print('context_dependent_conversation parsed question:', question) - return {'parsed_question': question} - - -def retrieve_topics_of_interest(state: GraphState): - print('retrieve_topics_of_interest') - # TODO: use a different extractor without question but the conversation input? - filters = { - 'people': get_filter_category_items(state.get('uid'), 'people'), - 'topics': get_filter_category_items(state.get('uid'), 'topics'), - 'entities': get_filter_category_items(state.get('uid'), 'entities'), - } - result = select_structured_filters(state.get('parsed_question', ''), filters) - return {'filters': { - 'topics': result.get('topics', []), - 'people': result.get('people', []), - 'entities': result.get('entities', []), - }} - - -def query_vectors(state: GraphState): - print('query_vectors') - uid = state.get('uid') - vector = generate_embedding(state.get('parsed_question', '')) if state.get('parsed_question') else [0] * 3072 - print('query_vectors vector:', vector[:5]) - memories_id = query_vectors_by_metadata( - uid, - vector, - dates_filter=[], - people=state.get('filters', {}).get('people', []), - topics=state.get('filters', {}).get('topics', []), - entities=state.get('filters', {}).get('entities', []), - dates=state.get('filters', {}).get('dates', []), - ) - memories = conversations_db.get_conversations_by_id(uid, memories_id) - return {'memories_found': memories} - - -def provide_answer(state: GraphState): - response: str = provide_advice_message( - state.get('uid'), - state.get('segments'), - Conversation.conversations_to_string(state.get('memories_found', []), True), - ) - return {'answer': response} - - -workflow = StateGraph(GraphState) - -workflow.add_edge(START, 'extract_question') -workflow.add_node("extract_question", extract_question) - -workflow.add_edge('extract_question', 'retrieve_topics_of_interest') -workflow.add_node("retrieve_topics_of_interest", retrieve_topics_of_interest) -workflow.add_edge('retrieve_topics_of_interest', 'query_vectors') - -workflow.add_node('query_vectors', query_vectors) -workflow.add_edge('query_vectors', 'provide_answer') -workflow.add_node('provide_answer', provide_answer) -workflow.add_edge('provide_answer', END) - -checkpointer = MemorySaver() -graph = workflow.compile(checkpointer=checkpointer) - - -@timeit -def execute_graph_realtime( - uid: str, segments: List[TranscriptSegment], use_full_transcript: bool = False -) -> Tuple[str, List[Conversation]]: - segments = segments if len(segments) < 10 or use_full_transcript else segments[-10:] - result = graph.invoke({'uid': uid, 'segments': segments}, {"configurable": {"thread_id": str(uuid.uuid4())}}) - return result.get('answer'), result.get('memories_found', []) - - -def _pretty_print_conversation(messages: List[Message]): - for msg in messages: - print(f'{msg.sender}: {msg.text}') - - -if __name__ == '__main__': - # uid = 'ccQJWj5mwhSY1dwjS1FPFBfKIXe2' - # def _send_message(text: str, sender: str = 'human'): - # message = Message( - # id=str(uuid.uuid4()), text=text, created_at=datetime.datetime.now(datetime.timezone.utc), sender=sender, - # type='text' - # ) - # chat_db.add_message(uid, message.dict()) - - graph.get_graph().draw_png('workflow.png') - segments = [] - result = execute_graph_realtime('TtCJi59JTVXHmyUC6vUQ1d9U6cK2', [TranscriptSegment(**s) for s in segments]) - print('result:', result[0]) From 7c1050869e22b1e920d442137df8be48173a8bde Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Thu, 15 May 2025 12:12:21 -0700 Subject: [PATCH 059/213] remove plugin models --- backend/models/plugin.py | 104 --------------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 backend/models/plugin.py diff --git a/backend/models/plugin.py b/backend/models/plugin.py deleted file mode 100644 index f6b737cf2..000000000 --- a/backend/models/plugin.py +++ /dev/null @@ -1,104 +0,0 @@ -from datetime import datetime -from enum import Enum -from typing import List, Optional, Set - -from pydantic import BaseModel - - -class PluginReview(BaseModel): - uid: str - rated_at: datetime - score: float - review: str - - @classmethod - def from_json(cls, json_data: dict): - return cls( - uid=json_data['uid'], - ratedAt=datetime.fromisoformat(json_data['rated_at']), - score=json_data['score'], - review=json_data['review'], - ) - - -class AuthStep(BaseModel): - name: str - url: str - - -class ExternalIntegration(BaseModel): - triggers_on: str - webhook_url: str - setup_completed_url: Optional[str] = None - setup_instructions_file_path: str - auth_steps: Optional[List[AuthStep]] = [] - # setup_instructions_markdown: str = '' - - -class ProactiveNotification(BaseModel): - scopes: Set[str] - - -class Plugin(BaseModel): - id: str - name: str - author: str - description: str - image: str # TODO: return image_url: str with the whole repo + path - capabilities: Set[str] - memory_prompt: Optional[str] = None - chat_prompt: Optional[str] = None - external_integration: Optional[ExternalIntegration] = None - reviews: List[PluginReview] = [] - user_review: Optional[PluginReview] = None - rating_avg: Optional[float] = 0 - rating_count: int = 0 - enabled: bool = False - deleted: bool = False - trigger_workflow_memories: bool = True # default true - installs: int = 0 - proactive_notification: Optional[ProactiveNotification] = None - created_at: Optional[datetime] = None - - def get_rating_avg(self) -> Optional[str]: - return f'{self.rating_avg:.1f}' if self.rating_avg is not None else None - - def has_capability(self, capability: str) -> bool: - return capability in self.capabilities - - def works_with_memories(self) -> bool: - return self.has_capability('memories') - - def works_with_chat(self) -> bool: - return self.has_capability('chat') - - def works_externally(self) -> bool: - return self.has_capability('external_integration') - - def triggers_on_memory_creation(self) -> bool: - return self.works_externally() and self.external_integration.triggers_on == 'memory_creation' - - def triggers_realtime(self) -> bool: - return self.works_externally() and self.external_integration.triggers_on == 'transcript_processed' - - def filter_proactive_notification_scopes(self, params: [str]) -> []: - if not self.proactive_notification: - return [] - return [param for param in params if param in self.proactive_notification.scopes] - - def get_image_url(self) -> str: - return f'https://raw.githubusercontent.com/BasedHardware/Omi/main{self.image}' - - -class UsageHistoryType(str, Enum): - memory_created_external_integration = 'memory_created_external_integration' - transcript_processed_external_integration = 'transcript_processed_external_integration' - memory_created_prompt = 'memory_created_prompt' - chat_message_sent = 'chat_message_sent' - - -class UsageHistoryItem(BaseModel): - uid: str - memory_id: Optional[str] = None - timestamp: datetime - type: UsageHistoryType From b8d2c4a52d62b7b7fb03783a88864348ec52860c Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Thu, 15 May 2025 12:37:29 -0700 Subject: [PATCH 060/213] remove deprecated routes, models and utils --- app/lib/backend/http/api/messages.dart | 59 +-------- app/lib/providers/message_provider.dart | 12 -- backend/database/processing_conversations.py | 99 -------------- backend/models/processing_conversation.py | 97 -------------- backend/routers/chat.py | 130 ++----------------- backend/routers/conversations.py | 19 +-- backend/routers/firmware.py | 66 +--------- backend/routers/integration.py | 6 +- backend/routers/postprocessing.py | 37 ------ backend/routers/processing_conversations.py | 86 ------------ backend/routers/screenpipe.py | 43 ------ backend/routers/speech_profile.py | 54 -------- backend/routers/transcribe.py | 59 +++++---- backend/utils/processing_conversations.py | 97 -------------- 14 files changed, 57 insertions(+), 807 deletions(-) delete mode 100644 backend/database/processing_conversations.py delete mode 100644 backend/models/processing_conversation.py delete mode 100644 backend/routers/postprocessing.py delete mode 100644 backend/routers/processing_conversations.py delete mode 100644 backend/routers/screenpipe.py delete mode 100644 backend/utils/processing_conversations.py diff --git a/app/lib/backend/http/api/messages.dart b/app/lib/backend/http/api/messages.dart index d804ab6a0..2325e528d 100644 --- a/app/lib/backend/http/api/messages.dart +++ b/app/lib/backend/http/api/messages.dart @@ -53,32 +53,6 @@ Future> clearChatServer({String? pluginId}) async { } } -Future sendMessageServer(String text, {String? appId, List? fileIds}) { - var url = '${Env.apiBaseUrl}v1/messages?plugin_id=$appId'; - if (appId == null || appId.isEmpty || appId == 'null' || appId == 'no_selected') { - url = '${Env.apiBaseUrl}v1/messages'; - } - return makeApiCall( - url: url, - headers: {}, - method: 'POST', - body: jsonEncode({'text': text, 'file_ids': fileIds}), - ).then((response) { - if (response == null) throw Exception('Failed to send message'); - if (response.statusCode == 200) { - return ServerMessage.fromJson(jsonDecode(response.body)); - } else { - Logger.error('Failed to send message ${response.body}'); - CrashReporting.reportHandledCrash( - Exception('Failed to send message ${response.body}'), - StackTrace.current, - level: NonFatalExceptionLevel.error, - ); - return ServerMessage.failedMessage(); - } - }); -} - ServerMessageChunk? parseMessageChunk(String line, String messageId) { if (line.startsWith('think: ')) { return ServerMessageChunk(messageId, line.substring(7).replaceAll("__CRLF__", "\n"), MessageChunkType.think); @@ -235,32 +209,6 @@ Stream sendVoiceMessageStreamServer(List files) async* } } -Future> sendVoiceMessageServer(List files) async { - var request = http.MultipartRequest( - 'POST', - Uri.parse('${Env.apiBaseUrl}v1/voice-messages'), - ); - for (var file in files) { - request.files.add(await http.MultipartFile.fromPath('files', file.path, filename: basename(file.path))); - } - request.headers.addAll({'Authorization': await getAuthHeader()}); - - try { - var streamedResponse = await request.send(); - var response = await http.Response.fromStream(streamedResponse); - if (response.statusCode == 200) { - debugPrint('sendVoiceMessageServer response body: ${jsonDecode(response.body)}'); - return ((jsonDecode(response.body) ?? []) as List).map((m) => ServerMessage.fromJson(m)).toList(); - } else { - debugPrint('Failed to upload sample. Status code: ${response.statusCode} ${response.body}'); - throw Exception('Failed to upload sample. Status code: ${response.statusCode}'); - } - } catch (e) { - debugPrint('An error occurred uploadSample: $e'); - throw Exception('An error occurred uploadSample: $e'); - } -} - Future?> uploadFilesServer(List files, {String? appId}) async { var url = '${Env.apiBaseUrl}v1/files?plugin_id=$appId'; if (appId == null || appId.isEmpty || appId == 'null' || appId == 'no_selected') { @@ -312,20 +260,19 @@ Future reportMessageServer(String messageId) async { } } - Future transcribeVoiceMessage(File audioFile) async { try { var request = http.MultipartRequest( 'POST', Uri.parse('${Env.apiBaseUrl}v1/voice-message/transcribe'), ); - + request.headers.addAll({'Authorization': await getAuthHeader()}); request.files.add(await http.MultipartFile.fromPath('files', audioFile.path)); - + var streamedResponse = await request.send(); var response = await http.Response.fromStream(streamedResponse); - + if (response.statusCode == 200) { final data = jsonDecode(response.body); return data['transcript'] ?? ''; diff --git a/app/lib/providers/message_provider.dart b/app/lib/providers/message_provider.dart index 0c4cc1b1d..d1a6f8e31 100644 --- a/app/lib/providers/message_provider.dart +++ b/app/lib/providers/message_provider.dart @@ -412,18 +412,6 @@ class MessageProvider extends ChangeNotifier { setShowTypingIndicator(false); } - Future sendMessageToServer(String text, String? appId) async { - setShowTypingIndicator(true); - messages.insert(0, ServerMessage.empty(appId: appId)); - List fileIds = uploadedFiles.map((e) => e.id).toList(); - var mes = await sendMessageServer(text, appId: appId, fileIds: fileIds); - if (messages[0].id == '0000') { - messages[0] = mes; - } - setShowTypingIndicator(false); - notifyListeners(); - } - Future sendInitialAppMessage(App? app) async { setSendingMessage(true); ServerMessage message = await getInitialAppMessage(app?.id); diff --git a/backend/database/processing_conversations.py b/backend/database/processing_conversations.py deleted file mode 100644 index 63d19de38..000000000 --- a/backend/database/processing_conversations.py +++ /dev/null @@ -1,99 +0,0 @@ -# DEPRECATED: This file has been deprecated long ago -# -# This file is deprecated and should be removed. The code is not used anymore and is not referenced in any other file. -# The only files that references this file are routers/processing_memories.py and utils/processing_conversations.py, which are also deprecated. - -from datetime import datetime -from typing import List - -from google.cloud import firestore -from google.cloud.firestore_v1 import FieldFilter - -from ._client import db - - -def upsert_processing_conversation(uid: str, processing_conversation_data: dict): - user_ref = db.collection('users').document(uid) - processing_conversation_ref = user_ref.collection('processing_memories').document(processing_conversation_data['id']) - processing_conversation_ref.set(processing_conversation_data) - - -def update_processing_conversation(uid: str, processing_conversation_id: str, memoy_data: dict): - user_ref = db.collection('users').document(uid) - processing_conversation_ref = user_ref.collection('processing_memories').document(processing_conversation_id) - processing_conversation_ref.update(memoy_data) - - -def delete_processing_conversation(uid, processing_conversation_id): - user_ref = db.collection('users').document(uid) - processing_conversation_ref = user_ref.collection('processing_memories').document(processing_conversation_id) - processing_conversation_ref.update({'deleted': True}) - - -def get_processing_conversations_by_id(uid, processing_conversation_ids): - user_ref = db.collection('users').document(uid) - conversations_ref = user_ref.collection('processing_memories') - - doc_refs = [conversations_ref.document(str(processing_conversation_id)) for processing_conversation_id in processing_conversation_ids] - docs = db.get_all(doc_refs) - - conversations = [] - for doc in docs: - if doc.exists: - conversations.append(doc.to_dict()) - return conversations - - -def get_processing_conversation_by_id(uid, processing_conversation_id): - conversation_ref = db.collection('users').document(uid).collection('processing_memories').document(processing_conversation_id) - return conversation_ref.get().to_dict() - - -def get_processing_conversations(uid: str, statuses: [str] = [], filter_ids: [str] = [], limit: int = 5): - processing_conversations_ref = ( - db.collection('users').document(uid).collection('processing_memories') - ) - if len(statuses) > 0: - processing_conversations_ref = processing_conversations_ref.where(filter=FieldFilter('status', 'in', statuses)) - if len(filter_ids) > 0: - processing_conversations_ref = processing_conversations_ref.where(filter=FieldFilter('id', 'in', filter_ids)) - processing_conversations_ref = processing_conversations_ref.order_by('created_at', direction=firestore.Query.DESCENDING) - processing_conversations_ref = processing_conversations_ref.limit(limit) - return [doc.to_dict() for doc in processing_conversations_ref.stream()] - - -def update_processing_conversation_segments(uid: str, id: str, segments: List[dict], capturing_to: datetime): - user_ref = db.collection('users').document(uid) - conversation_ref = user_ref.collection('processing_memories').document(id) - conversation_ref.update({ - 'transcript_segments': segments, - 'capturing_to': capturing_to, - }) - - -def update_processing_conversation_status(uid: str, id: str, status: str): - user_ref = db.collection('users').document(uid) - conversation_ref = user_ref.collection('processing_memories').document(id) - conversation_ref.update({ - 'status': status, - }) - - -def update_audio_url(uid: str, id: str, audio_url: str): - user_ref = db.collection('users').document(uid) - conversation_ref = user_ref.collection('processing_memories').document(id) - conversation_ref.update({ - 'audio_url': audio_url, - }) - - -def get_last(uid: str): - processing_conversations_ref = ( - db.collection('users').document(uid).collection('processing_memories') - ) - processing_conversations_ref = processing_conversations_ref.order_by('created_at', direction=firestore.Query.DESCENDING) - processing_conversations_ref = processing_conversations_ref.limit(1) - docs = [doc.to_dict() for doc in processing_conversations_ref.stream()] - if len(docs) > 0: - return docs[0] - return None diff --git a/backend/models/processing_conversation.py b/backend/models/processing_conversation.py deleted file mode 100644 index b8323ada4..000000000 --- a/backend/models/processing_conversation.py +++ /dev/null @@ -1,97 +0,0 @@ -# DEPRECATED: This file has been deprecated long ago -# -# This file is deprecated and should be removed. The code is not used anymore and is not referenced in any other file. -# The only files that references this file are routers/processing_memories.py and utils/processing_conversations, which are also deprecated. - -from datetime import datetime, timezone -from enum import Enum -from typing import List, Optional - -from pydantic import BaseModel - -from models.conversation import Geolocation -from models.transcript_segment import TranscriptSegment - - -class ProcessingConversationStatus(str, Enum): - Capturing = 'capturing' - Processing = 'processing' - Done = 'done' - Failed = 'failed' - - -class ProcessingConversation(BaseModel): - id: str - session_id: Optional[str] = None - session_ids: List[str] = [] - audio_url: Optional[str] = None - created_at: datetime - capturing_to: Optional[datetime] = None - status: Optional[ProcessingConversationStatus] = None - timer_start: float - timer_segment_start: Optional[float] = None - timer_starts: List[float] = [] - language: Optional[str] = None # applies only to Friend/Omi # TODO: once released migrate db to default 'en' - transcript_segments: List[TranscriptSegment] = [] - geolocation: Optional[Geolocation] = None - emotional_feedback: Optional[bool] = False - - memory_id: Optional[str] = None - message_ids: List[str] = [] - - @staticmethod - def predict_capturing_to(processing_conversation, min_seconds_limit: int): - timer_segment_start = processing_conversation.timer_segment_start if processing_conversation.timer_segment_start else processing_conversation.timer_start - segment_end = processing_conversation.transcript_segments[-1].end if len( - processing_conversation.transcript_segments) > 0 else 0 - return datetime.fromtimestamp(timer_segment_start + segment_end + min_seconds_limit, timezone.utc) - - -class BasicProcessingConversation(BaseModel): - id: str - timer_start: float - created_at: datetime - capturing_to: Optional[datetime] = None - status: Optional[ProcessingConversationStatus] = None - geolocation: Optional[Geolocation] = None - emotional_feedback: Optional[bool] = False - memory_id: Optional[str] = None - - -class DetailProcessingConversation(BaseModel): - id: str - timer_start: float - created_at: datetime - capturing_to: Optional[datetime] = None - status: Optional[ProcessingConversationStatus] = None - geolocation: Optional[Geolocation] = None - emotional_feedback: Optional[bool] = False - transcript_segments: List[TranscriptSegment] = [] - memory_id: Optional[str] = None - - -class UpdateProcessingConversation(BaseModel): - id: Optional[str] = None - capturing_to: Optional[datetime] = None - geolocation: Optional[Geolocation] = None - emotional_feedback: Optional[bool] = False - - -class UpdateProcessingConversationResponse(BaseModel): - result: BasicProcessingConversation - - -class DetailProcessingConversationResponse(BaseModel): - result: DetailProcessingConversation - - -class DetailProcessingConversationsResponse(BaseModel): - result: List[DetailProcessingConversation] - - -class BasicProcessingConversationResponse(BaseModel): - result: BasicProcessingConversation - - -class BasicProcessingMemoriesResponse(BaseModel): - result: List[BasicProcessingConversation] diff --git a/backend/routers/chat.py b/backend/routers/chat.py index 22f5ec2c6..755074cbc 100644 --- a/backend/routers/chat.py +++ b/backend/routers/chat.py @@ -15,9 +15,10 @@ from models.chat import ChatSession, Message, SendMessageRequest, MessageSender, ResponseMessage, MessageConversation, \ FileChat from models.conversation import Conversation -from routers.sync import retrieve_file_paths, decode_files_to_wav, retrieve_vad_segments +from routers.sync import retrieve_file_paths, decode_files_to_wav from utils.apps import get_available_app_by_id -from utils.chat import process_voice_message_segment, process_voice_message_segment_stream, transcribe_voice_message_segment +from utils.chat import process_voice_message_segment, process_voice_message_segment_stream, \ + transcribe_voice_message_segment from utils.llm import initial_chat_message, initial_persona_chat_message from utils.other import endpoints as auth, storage from utils.other.chat_file import FileChatTool @@ -137,7 +138,8 @@ def process_message(response: str, callback_data: dict): async def generate_stream(): callback_data = {} - async for chunk in execute_graph_chat_stream(uid, messages, app, cited=True, callback_data=callback_data, chat_session=chat_session): + async for chunk in execute_graph_chat_stream(uid, messages, app, cited=True, callback_data=callback_data, + chat_session=chat_session): if chunk: msg = chunk.replace("\n", "__CRLF__") yield f'{msg}\n\n' @@ -171,82 +173,6 @@ def report_message( chat_db.report_message(uid, msg_doc_id) return {'message': 'Message reported'} -@router.post('/v1/messages', tags=['chat'], response_model=ResponseMessage) -def send_message_v1( - data: SendMessageRequest, plugin_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid) -): - print('send_message', data.text, plugin_id, uid) - - if plugin_id in ['null', '']: - plugin_id = None - - message = Message( - id=str(uuid.uuid4()), text=data.text, created_at=datetime.now(timezone.utc), sender='human', type='text', - plugin_id=plugin_id, - ) - - chat_db.add_message(uid, message.dict()) - - app = get_available_app_by_id(plugin_id, uid) - app = App(**app) if app else None - - app_id = app.id if app else None - - messages = list(reversed([Message(**msg) for msg in chat_db.get_messages(uid, limit=10, plugin_id=plugin_id)])) - - response, ask_for_nps, memories = execute_graph_chat(uid, messages, app, cited=True) # plugin - - # cited extraction - cited_conversation_idxs = {int(i) for i in re.findall(r'\[(\d+)\]', response)} - if len(cited_conversation_idxs) > 0: - response = re.sub(r'\[\d+\]', '', response) - memories = [memories[i - 1] for i in cited_conversation_idxs if 0 < i and i <= len(memories)] - - memories_id = [] - # check if the items in the conversations list are dict - if memories: - converted_memories = [] - for m in memories[:5]: - if isinstance(m, dict): - converted_memories.append(Conversation(**m)) - else: - converted_memories.append(m) - memories_id = [m.id for m in converted_memories] - ai_message = Message( - id=str(uuid.uuid4()), - text=response, - created_at=datetime.now(timezone.utc), - sender='ai', - plugin_id=app_id, - type='text', - memories_id=memories_id, - ) - - chat_db.add_message(uid, ai_message.dict()) - ai_message.memories = memories if len(memories) < 5 else memories[:5] - if app_id: - record_app_usage(uid, app_id, UsageHistoryType.chat_message_sent, message_id=ai_message.id) - - resp = ai_message.dict() - resp['ask_for_nps'] = ask_for_nps - return resp - - -@router.post('/v1/messages/upload', tags=['chat'], response_model=ResponseMessage) -async def send_message_with_file( - file: UploadFile = File(...), plugin_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid) -): - print('send_message_with_file', file.filename, plugin_id, uid) - content = await file.read() - # TODO: steps - # - File should be uploaded to cloud storage - # - File content should be extracted and parsed, then sent to LLM, and ask it to "read it" say 5 words, and say "What questions do you have?" - # - Follow up questions, in langgraph should go through the path selection, and if referring to the file - # - A new graph path should be created that references the previous file. - # - if an image is received, it should ask gpt4vision for a description, but this is probably a different path - # - Limit content of the file to 10000 tokens, otherwise is too big. - # - If file is too big, it should do a mini RAG (later) - @router.delete('/v1/messages', tags=['chat'], response_model=Message) def clear_chat_messages(plugin_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid)): @@ -317,14 +243,6 @@ def create_initial_message(plugin_id: Optional[str], uid: str = Depends(auth.get return initial_message_util(uid, plugin_id) -@router.get('/v1/messages', response_model=List[Message], tags=['chat']) -def get_messages_v1(uid: str = Depends(auth.get_current_user_uid)): - messages = chat_db.get_messages(uid, limit=100, include_memories=True) - if not messages: - return [initial_message_util(uid)] - return messages - - @router.get('/v2/messages', response_model=List[Message], tags=['chat']) def get_messages(plugin_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid)): if plugin_id in ['null', '']: @@ -341,30 +259,6 @@ def get_messages(plugin_id: Optional[str] = None, uid: str = Depends(auth.get_cu return messages -@router.post("/v1/voice-messages") -async def create_voice_message(files: List[UploadFile] = File(...), uid: str = Depends(auth.get_current_user_uid)): - paths = retrieve_file_paths(files, uid) - if len(paths) == 0: - raise HTTPException(status_code=400, detail='Paths is invalid') - - # wav - wav_paths = decode_files_to_wav(paths) - if len(wav_paths) == 0: - raise HTTPException(status_code=400, detail='Wav path is invalid') - - # segmented - segmented_paths = set() - retrieve_vad_segments(wav_paths[0], segmented_paths) - if len(segmented_paths) == 0: - raise HTTPException(status_code=400, detail='Segmented paths is invalid') - - resp = process_voice_message_segment(list(segmented_paths)[0], uid) - if not resp: - raise HTTPException(status_code=400, detail='Bad params') - - return resp - - @router.post("/v2/voice-messages") async def create_voice_message_stream(files: List[UploadFile] = File(...), uid: str = Depends(auth.get_current_user_uid)): @@ -394,10 +288,10 @@ async def transcribe_voice_message(files: List[UploadFile] = File(...), # Check if files are empty if not files or len(files) == 0: raise HTTPException(status_code=400, detail='No files provided') - + wav_paths = [] other_file_paths = [] - + # Process all files in a single loop for file in files: if file.filename.lower().endswith('.wav'): @@ -411,28 +305,28 @@ async def transcribe_voice_message(files: List[UploadFile] = File(...), path = retrieve_file_paths([file], uid) if path: other_file_paths.extend(path) - + # Convert other files to WAV if needed if other_file_paths: converted_wav_paths = decode_files_to_wav(other_file_paths) if converted_wav_paths: wav_paths.extend(converted_wav_paths) - + # Process all WAV files for wav_path in wav_paths: transcript = transcribe_voice_message_segment(wav_path) - + # Clean up temporary WAV files created directly if wav_path.startswith(f"/tmp/{uid}_"): try: Path(wav_path).unlink() except: pass - + # If we got a transcript, return it if transcript: return {"transcript": transcript} - + # If we got here, no transcript was produced raise HTTPException(status_code=400, detail='Failed to transcribe audio') diff --git a/backend/routers/conversations.py b/backend/routers/conversations.py index 0d22b8d3c..5ab894c2c 100644 --- a/backend/routers/conversations.py +++ b/backend/routers/conversations.py @@ -1,7 +1,4 @@ -from fastapi import APIRouter, Depends, HTTPException, Request -from typing import Optional, List, Dict -from datetime import datetime -from pydantic import BaseModel +from fastapi import APIRouter, Depends, HTTPException import database.conversations as conversations_db import database.redis_db as redis_db @@ -19,9 +16,6 @@ router = APIRouter() - - - def _get_conversation_by_id(uid: str, conversation_id: str) -> dict: conversation = conversations_db.get_conversation(uid, conversation_id) if conversation is None or conversation.get('deleted', False): @@ -43,16 +37,6 @@ def process_in_progress_conversation(uid: str = Depends(auth.get_current_user_ui return CreateConversationResponse(conversation=conversation, messages=messages) -# class TranscriptRequest(BaseModel): -# transcript: str - -# @router.post('/v2/test-memory', response_model= [], tags=['conversations']) -# def process_test_memory( -# request: TranscriptRequest, uid: str = Depends(auth.get_current_user_uid) -# ): -# st = get_transcript_structure(request.transcript, datetime.now(),'en','Asia/Kolkata') -# return [st.json()] - @router.post('/v1/conversations/{conversation_id}/reprocess', response_model=Conversation, tags=['conversations']) def reprocess_conversation( conversation_id: str, language_code: Optional[str] = None, app_id: Optional[str] = None, @@ -377,7 +361,6 @@ def search_conversations_endpoint(search_request: SearchRequest, uid: str = Depe end_date=end_timestamp) - @router.post("/v1/conversations/{conversation_id}/test-prompt", response_model=dict, tags=['conversations']) def test_prompt(conversation_id: str, request: TestPromptRequest, uid: str = Depends(auth.get_current_user_uid)): conversation_data = _get_conversation_by_id(uid, conversation_id) diff --git a/backend/routers/firmware.py b/backend/routers/firmware.py index 8f008e7e0..51214afbf 100644 --- a/backend/routers/firmware.py +++ b/backend/routers/firmware.py @@ -9,6 +9,7 @@ from database.redis_db import get_generic_cache, set_generic_cache + class DeviceModel(int, Enum): OMI_DEVKIT_1 = 1 OMI_DEVKIT_2 = 2 @@ -36,6 +37,7 @@ def _get_device_by_model_number(device_model: str): return None + async def get_omi_github_releases(cache_key: str) -> Optional[list]: """Fetch releases from GitHub API with caching""" @@ -144,68 +146,6 @@ async def get_latest_version(device_model: str, firmware_revision: str, hardware } -@router.get("/v1/firmware/latest") -async def get_latest_version_v1(device: int): - # if device = 1 : Friend - # if device = 2 : OpenGlass - if device != 1 and device != 2: - raise HTTPException(status_code=404, detail="Device not found") - async with httpx.AsyncClient() as client: - url = "https://api.github.com/repos/basedhardware/omi/releases" - headers = { - "Accept": "application/vnd.github+json", - "X-GitHub-Api-Version": "2022-11-28", - "Authorization": f"Bearer {os.getenv('GITHUB_TOKEN')}", - } - response = await client.get(url, headers=headers) - if response.status_code != 200: - raise HTTPException(status_code=response.status_code, detail="Failed to fetch latest release") - releases = response.json() - latest_release = None - device_type = "friend" if device == 1 else "openglass" - for release in releases: - if ( - release.get("published_at") - and release.get("tag_name") - and (device_type in release.get("tag_name", "").lower() or device_type in release.get("name", "").lower()) - and "firmware" in release.get("tag_name", "").lower() - and not release.get("draft") - ): - if not latest_release: - latest_release = release - else: - if release.get("published_at") > latest_release.get("published_at"): - latest_release = release - if not latest_release: - raise HTTPException(status_code=404, detail="No latest release found for the device") - release_data = latest_release - kv = extract_key_value_pairs(release_data.get("body")) - assets = release_data.get("assets") - asset = None - for a in assets: - if "ota" in a.get("name", "").lower(): - asset = a - break - if not asset: - raise HTTPException(status_code=500, detail="No OTA zip found in the release") - return { - "version": kv.get("release_firmware_version"), - "min_version": kv.get("minimum_firmware_required"), - "min_app_version": kv.get("minimum_app_version"), - "min_app_version_code": kv.get("minimum_app_version_code"), - "device_type": kv.get("device_type"), - "id": release_data.get("id"), - "tag_name": release_data.get("tag_name"), - "published_at": release_data.get("published_at"), - "draft": release_data.get("draft"), - "prerelease": release_data.get("prerelease"), - "zip_url": asset.get("browser_download_url"), - "zip_name": asset.get("name"), - "zip_size": asset.get("size"), - "release_name": release_data.get("name"), - } - - def extract_key_value_pairs(markdown_content): if not markdown_content: return {} @@ -235,7 +175,7 @@ def extract_key_value_pairs(markdown_content): # Split by comma, filter empty strings key_value_map[key] = [step.strip() for step in value.split(',') if step.strip()] elif key == 'changelog': - # Split by pipe, filter empty strings + # Split by pipe, filter empty strings key_value_map[key] = [item.strip() for item in value.split('|') if item.strip()] else: key_value_map[key] = value diff --git a/backend/routers/integration.py b/backend/routers/integration.py index 4fe33e731..0f24654e7 100644 --- a/backend/routers/integration.py +++ b/backend/routers/integration.py @@ -1,9 +1,8 @@ import os from datetime import datetime, timedelta, timezone -from typing import Annotated, Optional, List, Tuple, Dict, Any, Union +from typing import Optional, List, Tuple, Union -from fastapi import APIRouter, Header, HTTPException, Depends, Query -import database.conversations as conversations_db +from fastapi import APIRouter, Header, HTTPException, Query from fastapi import Request from fastapi.responses import JSONResponse @@ -13,7 +12,6 @@ from utils.apps import verify_api_key import database.redis_db as redis_db import database.memories as memory_db -from models.memories import MemoryDB from database.redis_db import get_enabled_plugins, r as redis_client import database.notifications as notification_db import models.integrations as integration_models diff --git a/backend/routers/postprocessing.py b/backend/routers/postprocessing.py deleted file mode 100644 index b1e80cab7..000000000 --- a/backend/routers/postprocessing.py +++ /dev/null @@ -1,37 +0,0 @@ -# from fastapi import APIRouter, Depends, HTTPException, UploadFile -# -# from models.memory import * -# from utils.memories.postprocess_memory import postprocess_memory as postprocess_memory_util -# from utils.other import endpoints as auth -# -# router = APIRouter() -# -# -# @router.post("/v1/memories/{memory_id}/post-processing", response_model=Memory, tags=['memories']) -# def postprocess_memory( -# memory_id: str, file: Optional[UploadFile], emotional_feedback: Optional[bool] = False, -# uid: str = Depends(auth.get_current_user_uid) -# ): -# """ -# The objective of this endpoint, is to get the best possible transcript from the audio file. -# Instead of storing the initial deepgram result, doing a full post-processing with whisper-x. -# This increases the quality of transcript by at least 20%. -# Which also includes a better summarization. -# Which helps us create better vectors for the memory. -# And improves the overall experience of the user. -# """ -# -# # Save file -# file_path = f"_temp/{memory_id}_{file.filename}" -# with open(file_path, 'wb') as f: -# f.write(file.file.read()) -# -# # Process -# status_code, result = postprocess_memory_util( -# memory_id=memory_id, uid=uid, file_path=file_path, emotional_feedback=emotional_feedback, -# streaming_model="deepgram_streaming" -# ) -# if status_code != 200: -# raise HTTPException(status_code=status_code, detail=result) -# -# return result diff --git a/backend/routers/processing_conversations.py b/backend/routers/processing_conversations.py deleted file mode 100644 index ebca1997c..000000000 --- a/backend/routers/processing_conversations.py +++ /dev/null @@ -1,86 +0,0 @@ -# DEPRECATED: This file has been deprecated long ago -# -# This file is deprecated and should be removed. The code is not used anymore and is not referenced in any other file. - -from typing import Optional - -from fastapi import APIRouter, Depends, HTTPException - -import utils.processing_conversations as processing_conversation_utils -from models.processing_conversation import DetailProcessingConversationResponse, \ - DetailProcessingConversationsResponse, UpdateProcessingConversation, UpdateProcessingConversationResponse, \ - BasicProcessingConversation -from database.redis_db import cache_user_geolocation -from utils.other import endpoints as auth - -router = APIRouter() - - -# Deprecated -@router.patch("/v1/processing-memories/{processing_conversation_id}", - response_model=UpdateProcessingConversationResponse, - tags=['processing_memories']) -def update_processing_conversation( - processing_conversation_id: str, - updates_processing_conversation: UpdateProcessingConversation, - uid: str = Depends(auth.get_current_user_uid) -): - """ - Update ProcessingMemory endpoint. - :param processing_conversation_id: - :param updates_processing_conversation: data to update processing_memory - :param uid: user id. - :return: The new processing_memory updated. - """ - - print(f"Update processing conversation {processing_conversation_id}") - - # Keep up-to-date with the new logic - geolocation = updates_processing_conversation.geolocation - if geolocation: - cache_user_geolocation(uid, geolocation.dict()) - - processing_conversation = processing_conversation_utils.get_processing_conversation(uid, processing_conversation_id) - if not processing_conversation: - raise HTTPException(status_code=404, detail="Processing conversation not found") - - return UpdateProcessingConversationResponse(result=BasicProcessingConversation(**processing_conversation.dict())) - - -@router.get( - "/v1/processing-memories/{processing_conversation_id}", - response_model=DetailProcessingConversationResponse, - tags=['processing_memories'] -) -def get_processing_conversation(processing_conversation_id: str, uid: str = Depends(auth.get_current_user_uid)): - """ - Get ProcessingMemory endpoint. - :param processing_conversation_id: - :param uid: user id. - :return: The processing_memory. - """ - - # update_processing_memory.id = processing_memory_id - processing_conversation = processing_conversation_utils.get_processing_conversation(uid, processing_conversation_id) - if not processing_conversation: - raise HTTPException(status_code=404, detail="Processing conversation not found") - - return DetailProcessingConversationResponse(result=processing_conversation) - - -@router.get("/v1/processing-memories", response_model=DetailProcessingConversationsResponse, - tags=['processing_memories']) -def list_processing_conversation(uid: str = Depends(auth.get_current_user_uid), filter_ids: Optional[str] = None): - """ - List ProcessingMemory endpoint. - :param filter_ids: filter by processing_memory ids. - :param uid: user id. - :return: The list of processing_memories. - """ - processing_conversations = processing_conversation_utils.get_processing_memories( - uid, filter_ids=filter_ids.split(",") if filter_ids else [], limit=5 - ) - if not processing_conversations or len(processing_conversations) == 0: - return DetailProcessingConversationsResponse(result=[]) - - return DetailProcessingConversationsResponse(result=list(processing_conversations)) diff --git a/backend/routers/screenpipe.py b/backend/routers/screenpipe.py deleted file mode 100644 index 02ece61a2..000000000 --- a/backend/routers/screenpipe.py +++ /dev/null @@ -1,43 +0,0 @@ -# import os -# import uuid -# from datetime import datetime, timezone -# -# from fastapi import APIRouter -# from fastapi import Request, HTTPException -# -# from database.memories import upsert_memory -# from models.integrations import ScreenPipeCreateMemory -# from models.memory import Memory -# from utils.llm import get_transcript_structure, summarize_screen_pipe -# -# router = APIRouter() -# -# -# @router.post('/v1/integrations/screenpipe', response_model=Memory) -# def create_memory(request: Request, uid: str, data: ScreenPipeCreateMemory): -# if request.headers.get('api_key') != os.getenv('SCREENPIPE_API_KEY'): -# raise HTTPException(status_code=401, detail="Invalid API Key") -# -# if data.source == 'screen': -# structured = summarize_screen_pipe(data.text) -# elif data.source == 'audio': -# structured = get_transcript_structure(data.text, datetime.now(timezone.utc), 'en') -# else: -# raise HTTPException(status_code=400, detail='Invalid memory source') -# -# memory = Memory( -# id=str(uuid.uuid4()), -# uid=uid, -# structured=structured, -# started_at=datetime.now(timezone.utc), -# finished_at=datetime.now(timezone.utc), -# created_at=datetime.now(timezone.utc), -# discarded=False, -# deleted=False, -# source='screenpipe', -# ) -# -# output = memory.dict() -# output['external_data'] = data.dict() -# upsert_memory(uid, output) -# return output diff --git a/backend/routers/speech_profile.py b/backend/routers/speech_profile.py index 42fc2007a..e4b21b712 100644 --- a/backend/routers/speech_profile.py +++ b/backend/routers/speech_profile.py @@ -36,15 +36,6 @@ def get_speech_profile(uid: str = Depends(auth.get_current_user_uid)): # Consist of bytes (for initiating deepgram) # and audio itself, which we use on post-processing to use speechbrain model -@router.post('/v3/upload-bytes', tags=['v3']) -def upload_profile(data: UploadProfile, uid: str = Depends(auth.get_current_user_uid)): - if data.duration < 10: - raise HTTPException(status_code=400, detail="Audio duration is too short") - if data.duration > 120: - raise HTTPException(status_code=400, detail="Audio duration is too long") - - return {'status': 'ok'} - @router.post('/v3/upload-audio', tags=['v3']) def upload_profile(file: UploadFile, uid: str = Depends(auth.get_current_user_uid)): @@ -70,51 +61,6 @@ def upload_profile(file: UploadFile, uid: str = Depends(auth.get_current_user_ui # ********** SPEECH SAMPLES FROM CONVERSATION ********** # ****************************************************** - -def expand_speech_profile( - conversation_id: str, uid: str, segment_idx: int, assign_type: str, person_id: Optional[str] = None -): - print('expand_speech_profile', conversation_id, uid, segment_idx, assign_type, person_id) - if assign_type == 'is_user': - profile_path = get_profile_audio_if_exists(uid) - if not profile_path: # TODO: validate this in front - raise HTTPException(status_code=404, detail="Speech profile not found") - os.remove(profile_path) - else: - if not get_person(uid, person_id): - raise HTTPException(status_code=404, detail="Person not found") - - conversation_recording_path = get_conversation_recording_if_exists(uid, conversation_id) - if not conversation_recording_path: - raise HTTPException(status_code=404, detail="Conversation recording not found") - - conversation = get_conversation(uid, conversation_id) - if not conversation: - raise HTTPException(status_code=404, detail="Conversation not found") - - conversation = Conversation(**conversation) - segment = conversation.transcript_segments[segment_idx] - print('expand_speech_profile', segment) - aseg = AudioSegment.from_wav(conversation_recording_path) - segment_aseg = aseg[segment.start * 1000:segment.end * 1000] - os.remove(conversation_recording_path) - - segment_recording_path = f'_temp/{conversation_id}_segment_{segment_idx}.wav' - segment_aseg.export(segment_recording_path, format='wav') - - apply_vad_for_speech_profile(segment_recording_path) - - # remove file in all people + user profile - delete_additional_profile_audio(uid, segment_recording_path.split('/')[-1]) - delete_speech_sample_for_people(uid, segment_recording_path.split('/')[-1]) - - if assign_type == 'person_id': - upload_user_person_speech_sample(segment_recording_path, uid, person_id) - else: - upload_additional_profile_audio(segment_recording_path, uid) - return {"status": 'ok'} - - @router.delete('/v3/speech-profile/expand', tags=['v3']) def delete_extra_speech_profile_sample( memory_id: str, segment_idx: int, person_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid) diff --git a/backend/routers/transcribe.py b/backend/routers/transcribe.py index a66d49f11..c635865ff 100644 --- a/backend/routers/transcribe.py +++ b/backend/routers/transcribe.py @@ -17,7 +17,8 @@ from database import redis_db from database.redis_db import get_cached_user_geolocation from models.conversation import Conversation, TranscriptSegment, ConversationStatus, Structured, Geolocation -from models.message_event import ConversationEvent, MessageEvent, MessageServiceStatusEvent, LastConversationEvent, TranslationEvent +from models.message_event import ConversationEvent, MessageEvent, MessageServiceStatusEvent, LastConversationEvent, \ + TranslationEvent from models.transcript_segment import Translation from utils.apps import is_audio_bytes_app_enabled from utils.conversations.location import get_google_maps_location @@ -26,18 +27,19 @@ from utils.app_integrations import trigger_external_integrations from utils.stt.streaming import * from utils.stt.streaming import get_stt_service_for_language, STTService -from utils.stt.streaming import process_audio_soniox, process_audio_dg, process_audio_speechmatics, send_initial_file_path +from utils.stt.streaming import process_audio_soniox, process_audio_dg, process_audio_speechmatics, \ + send_initial_file_path from utils.webhooks import get_audio_bytes_webhook_seconds from utils.pusher import connect_to_trigger_pusher from utils.translation import translate_text, detect_language from utils.translation_cache import TranscriptSegmentLanguageCache - from utils.other import endpoints as auth from utils.other.storage import get_profile_audio_if_exists router = APIRouter() + async def _listen( websocket: WebSocket, uid: str, language: str = 'en', sample_rate: int = 8000, codec: str = 'pcm8', channels: int = 1, include_speech_profile: bool = True, stt_service: STTService = None, @@ -144,7 +146,8 @@ async def send_heartbeat(): # Start heart beat heartbeat_task = asyncio.create_task(send_heartbeat()) - _send_message_event(MessageServiceStatusEvent(event_type="service_status", status="initiating", status_text="Service Starting")) + _send_message_event( + MessageServiceStatusEvent(event_type="service_status", status="initiating", status_text="Service Starting")) # Validate user if not user_db.is_exists_user(uid): @@ -211,6 +214,7 @@ async def send_last_conversation(): last_conversation = conversations_db.get_last_completed_conversation(uid) if last_conversation: await _send_message_event(LastConversationEvent(memory_id=last_conversation['id'])) + asyncio.create_task(send_last_conversation()) async def _create_current_conversation(): @@ -249,24 +253,29 @@ def _process_in_progess_memories(): finished_at = datetime.fromisoformat(existing_conversation['finished_at'].isoformat()) seconds_since_last_segment = (datetime.now(timezone.utc) - finished_at).total_seconds() if seconds_since_last_segment >= conversation_creation_timeout: - print('_websocket_util processing existing_conversation', existing_conversation['id'], seconds_since_last_segment, uid) + print('_websocket_util processing existing_conversation', existing_conversation['id'], + seconds_since_last_segment, uid) asyncio.create_task(_create_current_conversation()) else: print('_websocket_util will process', existing_conversation['id'], 'in', conversation_creation_timeout - seconds_since_last_segment, 'seconds') conversation_creation_task = asyncio.create_task( - _trigger_create_conversation_with_delay(conversation_creation_timeout - seconds_since_last_segment, finished_at) + _trigger_create_conversation_with_delay(conversation_creation_timeout - seconds_since_last_segment, + finished_at) ) - _send_message_event(MessageServiceStatusEvent(status="in_progress_memories_processing", status_text="Processing Memories")) + _send_message_event( + MessageServiceStatusEvent(status="in_progress_memories_processing", status_text="Processing Memories")) _process_in_progess_memories() def _upsert_in_progress_conversation(segments: List[TranscriptSegment], finished_at: datetime): if existing := retrieve_in_progress_conversation(uid): conversation = Conversation(**existing) - conversation.transcript_segments, (starts, ends) = TranscriptSegment.combine_segments(conversation.transcript_segments, segments) + conversation.transcript_segments, (starts, ends) = TranscriptSegment.combine_segments( + conversation.transcript_segments, segments) conversations_db.update_conversation_segments(uid, conversation.id, - [segment.dict() for segment in conversation.transcript_segments]) + [segment.dict() for segment in + conversation.transcript_segments]) conversations_db.update_conversation_finished_at(uid, conversation.id, finished_at) redis_db.set_in_progress_conversation_id(uid, conversation.id) return conversation, (starts, ends) @@ -337,16 +346,19 @@ async def _process_stt(): try: file_path, speech_profile_duration = None, 0 # Thougts: how bee does for recognizing other languages speech profile? - if (language == 'en' or language == 'auto') and (codec == 'opus' or codec == 'pcm16') and include_speech_profile: + if (language == 'en' or language == 'auto') and ( + codec == 'opus' or codec == 'pcm16') and include_speech_profile: file_path = get_profile_audio_if_exists(uid) speech_profile_duration = AudioSegment.from_wav(file_path).duration_seconds + 5 if file_path else 0 # DEEPGRAM if stt_service == STTService.deepgram: deepgram_socket = await process_audio_dg( - stream_transcript, stt_language, sample_rate, 1, preseconds=speech_profile_duration, model=stt_model,) + stream_transcript, stt_language, sample_rate, 1, preseconds=speech_profile_duration, + model=stt_model, ) if speech_profile_duration: - deepgram_socket2 = await process_audio_dg(stream_transcript, stt_language, sample_rate, 1, model=stt_model) + deepgram_socket2 = await process_audio_dg(stream_transcript, stt_language, sample_rate, 1, + model=stt_model) async def deepgram_socket_send(data): return deepgram_socket.send(data) @@ -428,7 +440,9 @@ async def transcript_consume(): # 102|data data = bytearray() data.extend(struct.pack("I", 102)) - data.extend(bytes(json.dumps({"segments":segment_buffers,"memory_id":in_progress_conversation_id}), "utf-8")) + data.extend( + bytes(json.dumps({"segments": segment_buffers, "memory_id": in_progress_conversation_id}), + "utf-8")) segment_buffers = [] # reset await transcript_ws.send(data) except websockets.exceptions.ConnectionClosed as e: @@ -524,7 +538,8 @@ async def translate(segments: List[TranscriptSegment], conversation_id: str): if not segment_text or len(segment_text) <= 0: continue # Check cache for language detection result - is_previously_target_language, diff_text = language_cache.get_language_result(segment.id, segment_text, language) + is_previously_target_language, diff_text = language_cache.get_language_result(segment.id, segment_text, + language) if (is_previously_target_language is None or is_previously_target_language is True) \ and diff_text: try: @@ -639,7 +654,9 @@ async def stream_transcript_process(): segment["end"] -= seconds_to_trim segments[i] = segment - transcript_segments, _ = TranscriptSegment.combine_segments([], [TranscriptSegment(**segment) for segment in segments]) + transcript_segments, _ = TranscriptSegment.combine_segments([], + [TranscriptSegment(**segment) for segment in + segments]) # can trigger race condition? increase soniox utterance? conversation, (starts, ends) = _upsert_in_progress_conversation(transcript_segments, finished_at) @@ -813,16 +830,12 @@ async def receive_audio(dg_socket1, dg_socket2, soniox_socket, soniox_socket2, s print(f"Error closing Pusher: {e}", uid) print("_listen ended", uid) -@router.websocket("/v3/listen") -async def listen_handler_v3( - websocket: WebSocket, uid: str = Depends(auth.get_current_user_uid), language: str = 'en', sample_rate: int = 8000, codec: str = 'pcm8', - channels: int = 1, include_speech_profile: bool = True, stt_service: STTService = None -): - await _listen(websocket, uid, language, sample_rate, codec, channels, include_speech_profile, None) @router.websocket("/v4/listen") async def listen_handler( - websocket: WebSocket, uid: str = Depends(auth.get_current_user_uid), language: str = 'en', sample_rate: int = 8000, codec: str = 'pcm8', + websocket: WebSocket, uid: str = Depends(auth.get_current_user_uid), language: str = 'en', + sample_rate: int = 8000, codec: str = 'pcm8', channels: int = 1, include_speech_profile: bool = True, stt_service: STTService = None ): - await _listen(websocket, uid, language, sample_rate, codec, channels, include_speech_profile, None, including_combined_segments=True) + await _listen(websocket, uid, language, sample_rate, codec, channels, include_speech_profile, None, + including_combined_segments=True) diff --git a/backend/utils/processing_conversations.py b/backend/utils/processing_conversations.py deleted file mode 100644 index 79fbf397d..000000000 --- a/backend/utils/processing_conversations.py +++ /dev/null @@ -1,97 +0,0 @@ -# DEPRECATED: This file has been deprecated long ago -# -# This file is deprecated and should be removed. The code is not used anymore and is not referenced in any other file. -# The only file that references this file is routers/processing_memories.py, which is also deprecated. - -import time -from datetime import datetime, timezone - -import database.processing_conversations as processing_conversations_db -from database.redis_db import get_cached_user_geolocation -from models.conversation import CreateConversation, Geolocation -from models.processing_conversation import ProcessingConversation, ProcessingConversationStatus, DetailProcessingConversation -from utils.conversations.location import get_google_maps_location -from utils.conversations.process_conversation import process_conversation -from utils.app_integrations import trigger_external_integrations - - -async def create_conversation_by_processing_conversation(uid: str, processing_conversation_id: str): - # Fetch new - processing_conversations = processing_conversations_db.get_processing_conversations_by_id(uid, [processing_conversation_id]) - if len(processing_conversations) == 0: - print("processing conversation is not found") - return - processing_conversation = ProcessingConversation(**processing_conversations[0]) - - # Create conversation - transcript_segments = processing_conversation.transcript_segments - if not transcript_segments or len(transcript_segments) == 0: - print("Transcript segments is invalid") - return - timer_segment_start = processing_conversation.timer_segment_start if processing_conversation.timer_segment_start else processing_conversation.timer_start - segment_end = transcript_segments[-1].end - new_conversation = CreateConversation( - started_at=datetime.fromtimestamp(timer_segment_start, timezone.utc), - finished_at=datetime.fromtimestamp(timer_segment_start + segment_end, timezone.utc), - language=processing_conversation.language, - transcript_segments=transcript_segments, - ) - - # Geolocation - geolocation = get_cached_user_geolocation(uid) - if geolocation: - geolocation = Geolocation(**geolocation) - new_conversation.geolocation = get_google_maps_location(geolocation.latitude, geolocation.longitude) - - language_code = new_conversation.language - conversation = process_conversation(uid, language_code, new_conversation) - messages = trigger_external_integrations(uid, conversation) - - # update - processing_conversation.memory_id = conversation.id - processing_conversation.message_ids = list(map(lambda m: m.id, messages)) - processing_conversations_db.update_processing_conversation(uid, processing_conversation.id, processing_conversation.dict()) - - return conversation, messages, processing_conversation - - -def get_processing_conversation(uid: str, id: str, ) -> DetailProcessingConversation: - processing_conversation = processing_conversations_db.get_processing_conversation_by_id(uid, id) - if not processing_conversation: - print("processing conversation is not found") - return - processing_conversation = DetailProcessingConversation(**processing_conversation) - - return processing_conversation - - -def get_processing_memories(uid: str, filter_ids: [str] = [], limit: int = 3) -> [DetailProcessingConversation]: - processing_conversations = [] - tracking_status = False - if len(filter_ids) > 0: - filter_ids = list(set(filter_ids)) # prevent duplicated wastes - processing_conversations = processing_conversations_db.get_processing_conversations(uid, filter_ids=filter_ids, limit=limit) - else: - processing_conversations = processing_conversations_db.get_processing_conversations(uid, statuses=[ - ProcessingConversationStatus.Processing], limit=limit) - tracking_status = True - - if not processing_conversations or len(processing_conversations) == 0: - return [] - - resp = [DetailProcessingConversation(**processing_conversation) for processing_conversation in processing_conversations] - - # Tracking status - # Warn: it's suck, remove soon! - if tracking_status: - new_resp = [] - for pm in resp: - # Keep processing after 5m from the capturing to, there are something went wrong. - if pm.status == ProcessingConversationStatus.Processing and pm.capturing_to and pm.capturing_to.timestamp() < time.time() - 300: - pm.status = ProcessingConversationStatus.Failed - processing_conversations_db.update_processing_conversation_status(uid, pm.id, pm.status) - continue - new_resp.append(pm) - resp = new_resp - - return resp From 95b692ca96df2c1b4c6894b8596a81dc689ece81 Mon Sep 17 00:00:00 2001 From: Aarav Garg Date: Thu, 15 May 2025 12:51:59 -0700 Subject: [PATCH 061/213] fixed overflow error in language select popup header --- .../primary_language_widget.dart | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/app/lib/pages/onboarding/primary_language/primary_language_widget.dart b/app/lib/pages/onboarding/primary_language/primary_language_widget.dart index 5935aea8f..f7f0bf046 100644 --- a/app/lib/pages/onboarding/primary_language/primary_language_widget.dart +++ b/app/lib/pages/onboarding/primary_language/primary_language_widget.dart @@ -58,8 +58,7 @@ class _LanguageSelectorWidgetState extends State { filteredLanguages = List.from(languages); } else { filteredLanguages = languages.where((lang) { - return lang.key.toLowerCase().contains(searchQuery) || - lang.value.toLowerCase().contains(searchQuery); + return lang.key.toLowerCase().contains(searchQuery) || lang.value.toLowerCase().contains(searchQuery); }).toList(); } @@ -82,10 +81,6 @@ class _LanguageSelectorWidgetState extends State { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - IconButton( - icon: const Icon(Icons.close, color: Colors.white), - onPressed: () => Navigator.pop(context), - ), const Text( 'Select your primary language', style: TextStyle( @@ -213,8 +208,7 @@ class _PrimaryLanguageWidgetState extends State { // Find the language name for the saved language code final homeProvider = Provider.of(context, listen: false); try { - selectedLanguageName = - homeProvider.availableLanguages.entries.firstWhere((entry) => entry.value == savedLanguage).key; + selectedLanguageName = homeProvider.availableLanguages.entries.firstWhere((entry) => entry.value == savedLanguage).key; } catch (e) { // If language not found in the map, just use the code selectedLanguageName = savedLanguage; @@ -305,12 +299,7 @@ class _PrimaryLanguageWidgetState extends State { width: double.infinity, decoration: BoxDecoration( border: const GradientBoxBorder( - gradient: LinearGradient(colors: [ - Color.fromARGB(127, 208, 208, 208), - Color.fromARGB(127, 188, 99, 121), - Color.fromARGB(127, 86, 101, 182), - Color.fromARGB(127, 126, 190, 236) - ]), + gradient: LinearGradient(colors: [Color.fromARGB(127, 208, 208, 208), Color.fromARGB(127, 188, 99, 121), Color.fromARGB(127, 86, 101, 182), Color.fromARGB(127, 126, 190, 236)]), width: 2, ), borderRadius: BorderRadius.circular(12), From 3c828dd1b13a411336b723ee351dd33906ffcf12 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Thu, 15 May 2025 12:59:44 -0700 Subject: [PATCH 062/213] consolidate chat endpoint versions --- app/lib/backend/http/api/messages.dart | 12 +- backend/database/chat.py | 4 +- backend/routers/chat.py | 169 +++++++++++++++++++++++-- 3 files changed, 165 insertions(+), 20 deletions(-) diff --git a/app/lib/backend/http/api/messages.dart b/app/lib/backend/http/api/messages.dart index 2325e528d..44bd0723b 100644 --- a/app/lib/backend/http/api/messages.dart +++ b/app/lib/backend/http/api/messages.dart @@ -40,7 +40,7 @@ Future> getMessagesServer({ Future> clearChatServer({String? pluginId}) async { if (pluginId == 'no_selected') pluginId = null; var response = await makeApiCall( - url: '${Env.apiBaseUrl}v1/messages?plugin_id=${pluginId ?? ''}', + url: '${Env.apiBaseUrl}v2/messages?plugin_id=${pluginId ?? ''}', headers: {}, method: 'DELETE', body: '', @@ -138,7 +138,7 @@ Stream sendMessageStreamServer(String text, {String? appId, Future getInitialAppMessage(String? appId) { return makeApiCall( - url: '${Env.apiBaseUrl}v1/initial-message?plugin_id=$appId', + url: '${Env.apiBaseUrl}v2/initial-message?app_id=$appId', headers: {}, method: 'POST', body: '', @@ -210,9 +210,9 @@ Stream sendVoiceMessageStreamServer(List files) async* } Future?> uploadFilesServer(List files, {String? appId}) async { - var url = '${Env.apiBaseUrl}v1/files?plugin_id=$appId'; + var url = '${Env.apiBaseUrl}v2/files?app_id=$appId'; if (appId == null || appId.isEmpty || appId == 'null' || appId == 'no_selected') { - url = '${Env.apiBaseUrl}v1/files'; + url = '${Env.apiBaseUrl}v2/files'; } var request = http.MultipartRequest( 'POST', @@ -249,7 +249,7 @@ Future?> uploadFilesServer(List files, {String? appId}) Future reportMessageServer(String messageId) async { var response = await makeApiCall( - url: '${Env.apiBaseUrl}v1/messages/$messageId/report', + url: '${Env.apiBaseUrl}v2/messages/$messageId/report', headers: {}, method: 'POST', body: '', @@ -264,7 +264,7 @@ Future transcribeVoiceMessage(File audioFile) async { try { var request = http.MultipartRequest( 'POST', - Uri.parse('${Env.apiBaseUrl}v1/voice-message/transcribe'), + Uri.parse('${Env.apiBaseUrl}v2/voice-message/transcribe'), ); request.headers.addAll({'Authorization': await getAuthHeader()}); diff --git a/backend/database/chat.py b/backend/database/chat.py index 5b64b8fbe..238abc3ee 100644 --- a/backend/database/chat.py +++ b/backend/database/chat.py @@ -228,13 +228,13 @@ def batch_delete_messages(parent_doc_ref, batch_size=450, plugin_id: Optional[st last_doc = docs_list[-1] -def clear_chat(uid: str, plugin_id: Optional[str] = None, chat_session_id: Optional[str] = None): +def clear_chat(uid: str, app_id: Optional[str] = None, chat_session_id: Optional[str] = None): try: user_ref = db.collection('users').document(uid) print(f"Deleting messages for user: {uid}") if not user_ref.get().exists: return {"message": "User not found"} - batch_delete_messages(user_ref, plugin_id=plugin_id, chat_session_id=chat_session_id) + batch_delete_messages(user_ref, plugin_id=app_id, chat_session_id=chat_session_id) return None except Exception as e: return {"message": str(e)} diff --git a/backend/routers/chat.py b/backend/routers/chat.py index 755074cbc..a48dd706d 100644 --- a/backend/routers/chat.py +++ b/backend/routers/chat.py @@ -159,7 +159,7 @@ async def generate_stream(): ) -@router.post('/v1/messages/{message_id}/report', tags=['chat'], response_model=dict) +@router.post('/v2/messages/{message_id}/report', tags=['chat'], response_model=dict) def report_message( message_id: str, uid: str = Depends(auth.get_current_user_uid) ): @@ -174,16 +174,16 @@ def report_message( return {'message': 'Message reported'} -@router.delete('/v1/messages', tags=['chat'], response_model=Message) -def clear_chat_messages(plugin_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid)): - if plugin_id in ['null', '']: - plugin_id = None +@router.delete('/v2/messages', tags=['chat'], response_model=Message) +def clear_chat_messages(app_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid)): + if app_id in ['null', '']: + app_id = None # get current chat session - chat_session = chat_db.get_chat_session(uid, plugin_id=plugin_id) + chat_session = chat_db.get_chat_session(uid, plugin_id=app_id) chat_session_id = chat_session['id'] if chat_session else None - err = chat_db.clear_chat(uid, plugin_id=plugin_id, chat_session_id=chat_session_id) + err = chat_db.clear_chat(uid, app_id=app_id, chat_session_id=chat_session_id) if err: raise HTTPException(status_code=500, detail='Failed to clear chat') @@ -195,7 +195,7 @@ def clear_chat_messages(plugin_id: Optional[str] = None, uid: str = Depends(auth if chat_session_id is not None: chat_db.delete_chat_session(uid, chat_session_id) - return initial_message_util(uid, plugin_id) + return initial_message_util(uid, app_id) def initial_message_util(uid: str, app_id: Optional[str] = None): @@ -238,9 +238,9 @@ def initial_message_util(uid: str, app_id: Optional[str] = None): return ai_message -@router.post('/v1/initial-message', tags=['chat'], response_model=Message) -def create_initial_message(plugin_id: Optional[str], uid: str = Depends(auth.get_current_user_uid)): - return initial_message_util(uid, plugin_id) +@router.post('/v2/initial-message', tags=['chat'], response_model=Message) +def create_initial_message(app_id: Optional[str], uid: str = Depends(auth.get_current_user_uid)): + return initial_message_util(uid, app_id) @router.get('/v2/messages', response_model=List[Message], tags=['chat']) @@ -282,7 +282,7 @@ async def generate_stream(): ) -@router.post("/v1/voice-message/transcribe") +@router.post("/v2/voice-message/transcribe") async def transcribe_voice_message(files: List[UploadFile] = File(...), uid: str = Depends(auth.get_current_user_uid)): # Check if files are empty @@ -331,6 +331,58 @@ async def transcribe_voice_message(files: List[UploadFile] = File(...), raise HTTPException(status_code=400, detail='Failed to transcribe audio') +@router.post('/v2/files', response_model=List[FileChat], tags=['chat']) +def upload_file_chat(files: List[UploadFile] = File(...), uid: str = Depends(auth.get_current_user_uid)): + thumbs_name = [] + files_chat = [] + for file in files: + temp_file = Path(f"{file.filename}") + with temp_file.open("wb") as buffer: + shutil.copyfileobj(file.file, buffer) + + fc_tool = FileChatTool() + result = fc_tool.upload(temp_file) + + thumb_name = result.get("thumbnail_name", "") + if thumb_name != "": + thumbs_name.append(thumb_name) + + filechat = FileChat( + id=str(uuid.uuid4()), + name=result.get("file_name", ""), + mime_type=result.get("mime_type", ""), + openai_file_id=result.get("file_id", ""), + created_at=datetime.now(timezone.utc), + thumb_name=thumb_name, + ) + files_chat.append(filechat) + + # cleanup temp_file + temp_file.unlink() + + if len(thumbs_name) > 0: + thumbs_path = storage.upload_multi_chat_files(thumbs_name, uid) + for fc in files_chat: + if not fc.is_image(): + continue + thumb_path = thumbs_path.get(fc.thumb_name, "") + fc.thumbnail = thumb_path + # cleanup file thumb + thumb_file = Path(fc.thumb_name) + thumb_file.unlink() + + # save db + files_chat_dict = [fc.dict() for fc in files_chat] + + chat_db.add_multi_files(uid, files_chat_dict) + + response = [fc.dict() for fc in files_chat] + + return response + + +#CLEANUP: Remove after new app goes to prod ---------------------------------------------------------- + @router.post('/v1/files', response_model=List[FileChat], tags=['chat']) def upload_file_chat(files: List[UploadFile] = File(...), uid: str = Depends(auth.get_current_user_uid)): thumbs_name = [] @@ -379,3 +431,96 @@ def upload_file_chat(files: List[UploadFile] = File(...), uid: str = Depends(aut response = [fc.dict() for fc in files_chat] return response + + +@router.post('/v1/messages/{message_id}/report', tags=['chat'], response_model=dict) +def report_message( + message_id: str, uid: str = Depends(auth.get_current_user_uid) +): + message, msg_doc_id = chat_db.get_message(uid, message_id) + if message is None: + raise HTTPException(status_code=404, detail='Message not found') + if message.sender != 'ai': + raise HTTPException(status_code=400, detail='Only AI messages can be reported') + if message.reported: + raise HTTPException(status_code=400, detail='Message already reported') + chat_db.report_message(uid, msg_doc_id) + return {'message': 'Message reported'} + + +@router.delete('/v1/messages', tags=['chat'], response_model=Message) +def clear_chat_messages(plugin_id: Optional[str] = None, uid: str = Depends(auth.get_current_user_uid)): + if plugin_id in ['null', '']: + plugin_id = None + + # get current chat session + chat_session = chat_db.get_chat_session(uid, plugin_id=plugin_id) + chat_session_id = chat_session['id'] if chat_session else None + + err = chat_db.clear_chat(uid, app_id=plugin_id, chat_session_id=chat_session_id) + if err: + raise HTTPException(status_code=500, detail='Failed to clear chat') + + # clean thread chat file + fc_tool = FileChatTool() + fc_tool.cleanup(uid) + + # clear session + if chat_session_id is not None: + chat_db.delete_chat_session(uid, chat_session_id) + + return initial_message_util(uid, plugin_id) + + +@router.post("/v1/voice-message/transcribe") +async def transcribe_voice_message(files: List[UploadFile] = File(...), + uid: str = Depends(auth.get_current_user_uid)): + # Check if files are empty + if not files or len(files) == 0: + raise HTTPException(status_code=400, detail='No files provided') + + wav_paths = [] + other_file_paths = [] + + # Process all files in a single loop + for file in files: + if file.filename.lower().endswith('.wav'): + # For WAV files, save directly to a temporary path + temp_path = f"/tmp/{uid}_{uuid.uuid4()}.wav" + with open(temp_path, "wb") as buffer: + shutil.copyfileobj(file.file, buffer) + wav_paths.append(temp_path) + else: + # For other files, collect paths for later conversion + path = retrieve_file_paths([file], uid) + if path: + other_file_paths.extend(path) + + # Convert other files to WAV if needed + if other_file_paths: + converted_wav_paths = decode_files_to_wav(other_file_paths) + if converted_wav_paths: + wav_paths.extend(converted_wav_paths) + + # Process all WAV files + for wav_path in wav_paths: + transcript = transcribe_voice_message_segment(wav_path) + + # Clean up temporary WAV files created directly + if wav_path.startswith(f"/tmp/{uid}_"): + try: + Path(wav_path).unlink() + except: + pass + + # If we got a transcript, return it + if transcript: + return {"transcript": transcript} + + # If we got here, no transcript was produced + raise HTTPException(status_code=400, detail='Failed to transcribe audio') + + +@router.post('/v1/initial-message', tags=['chat'], response_model=Message) +def create_initial_message(plugin_id: Optional[str], uid: str = Depends(auth.get_current_user_uid)): + return initial_message_util(uid, plugin_id) From 2143677f6cb40ffdc619c97d6022832491db0541 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Thu, 15 May 2025 17:03:57 -0700 Subject: [PATCH 063/213] split llm.py file into multiple files --- backend/database/vector_db.py | 2 +- backend/main.py | 3 +- backend/routers/apps.py | 3 +- backend/routers/chat.py | 3 +- backend/routers/conversations.py | 2 +- backend/routers/mcp.py | 3 +- backend/routers/memories.py | 2 +- backend/routers/users.py | 2 +- backend/scripts/rag/app.py | 2 +- backend/scripts/rag/memories.py | 2 +- backend/utils/app_integrations.py | 6 +- backend/utils/apps.py | 2 +- backend/utils/conversations/memories.py | 2 +- .../conversations/process_conversation.py | 16 +- backend/utils/llm.py | 1554 +---------------- backend/utils/llm/__init__.py | 0 backend/utils/llm/chat.py | 820 +++++++++ backend/utils/llm/clients.py | 45 + backend/utils/llm/conversation_processing.py | 261 +++ backend/utils/llm/external_integrations.py | 80 + backend/utils/llm/followup.py | 27 + backend/utils/llm/memories.py | 137 ++ backend/utils/llm/openglass.py | 19 + backend/utils/llm/persona.py | 211 +++ backend/utils/llm/proactive_notification.py | 30 + backend/utils/llm/trends.py | 59 + backend/utils/other/notifications.py | 2 +- backend/utils/retrieval/graph.py | 4 +- backend/utils/retrieval/rag.py | 3 +- backend/utils/social.py | 2 +- 30 files changed, 1733 insertions(+), 1571 deletions(-) create mode 100644 backend/utils/llm/__init__.py create mode 100644 backend/utils/llm/chat.py create mode 100644 backend/utils/llm/clients.py create mode 100644 backend/utils/llm/conversation_processing.py create mode 100644 backend/utils/llm/external_integrations.py create mode 100644 backend/utils/llm/followup.py create mode 100644 backend/utils/llm/memories.py create mode 100644 backend/utils/llm/openglass.py create mode 100644 backend/utils/llm/persona.py create mode 100644 backend/utils/llm/proactive_notification.py create mode 100644 backend/utils/llm/trends.py diff --git a/backend/database/vector_db.py b/backend/database/vector_db.py index 34c2a2491..86e843b1c 100644 --- a/backend/database/vector_db.py +++ b/backend/database/vector_db.py @@ -7,7 +7,7 @@ from pinecone import Pinecone from models.conversation import Conversation -from utils.llm import embeddings +from utils.llm.clients import embeddings if os.getenv('PINECONE_API_KEY') is not None: pc = Pinecone(api_key=os.getenv('PINECONE_API_KEY', '')) diff --git a/backend/main.py b/backend/main.py index b7dc05b44..0851a62f3 100644 --- a/backend/main.py +++ b/backend/main.py @@ -6,7 +6,7 @@ from modal import Image, App, asgi_app, Secret from routers import workflow, chat, firmware, plugins, transcribe, notifications, \ - speech_profile, agents, users, processing_conversations, trends, sync, apps, custom_auth, \ + speech_profile, agents, users, trends, sync, apps, custom_auth, \ payment, integration, conversations, memories, mcp from utils.other.timeout import TimeoutMiddleware @@ -31,7 +31,6 @@ app.include_router(integration.router) app.include_router(agents.router) app.include_router(users.router) -app.include_router(processing_conversations.router) app.include_router(trends.router) app.include_router(firmware.router) diff --git a/backend/routers/apps.py b/backend/routers/apps.py index 416a24aa8..c3747bfda 100644 --- a/backend/routers/apps.py +++ b/backend/routers/apps.py @@ -25,8 +25,7 @@ from database.memories import migrate_memories -from utils.llm import generate_description, generate_persona_intro_message - +from utils.llm.persona import generate_persona_intro_message, generate_description from utils.notifications import send_notification from utils.other import endpoints as auth from models.app import App, ActionType, AppCreate, AppUpdate diff --git a/backend/routers/chat.py b/backend/routers/chat.py index a48dd706d..5b71339fa 100644 --- a/backend/routers/chat.py +++ b/backend/routers/chat.py @@ -19,7 +19,8 @@ from utils.apps import get_available_app_by_id from utils.chat import process_voice_message_segment, process_voice_message_segment_stream, \ transcribe_voice_message_segment -from utils.llm import initial_chat_message, initial_persona_chat_message +from utils.llm.persona import initial_persona_chat_message +from utils.llm.chat import initial_chat_message from utils.other import endpoints as auth, storage from utils.other.chat_file import FileChatTool from utils.retrieval.graph import execute_graph_chat, execute_graph_chat_stream, execute_persona_chat_stream diff --git a/backend/routers/conversations.py b/backend/routers/conversations.py index 5ab894c2c..69ffe7058 100644 --- a/backend/routers/conversations.py +++ b/backend/routers/conversations.py @@ -8,7 +8,7 @@ from utils.conversations.process_conversation import process_conversation, retrieve_in_progress_conversation from utils.conversations.search import search_conversations -from utils.llm import generate_summary_with_prompt +from utils.llm.conversation_processing import generate_summary_with_prompt from utils.other import endpoints as auth from utils.other.storage import get_conversation_recording_if_exists from utils.app_integrations import trigger_external_integrations diff --git a/backend/routers/mcp.py b/backend/routers/mcp.py index e8709c5cf..982c3a688 100644 --- a/backend/routers/mcp.py +++ b/backend/routers/mcp.py @@ -13,9 +13,10 @@ from models.memories import MemoryDB, Memory, MemoryCategory from models.memory import CategoryEnum from utils.apps import update_personas_async -from utils.llm import identify_category_for_memory from firebase_admin import auth +from utils.llm.memories import identify_category_for_memory + router = APIRouter() diff --git a/backend/routers/memories.py b/backend/routers/memories.py index e6b8f60aa..64578a8e8 100644 --- a/backend/routers/memories.py +++ b/backend/routers/memories.py @@ -6,7 +6,7 @@ import database.memories as memories_db from models.memories import MemoryDB, Memory, MemoryCategory from utils.apps import update_personas_async -from utils.llm import identify_category_for_memory +from utils.llm.memories import identify_category_for_memory from utils.other import endpoints as auth router = APIRouter() diff --git a/backend/routers/users.py b/backend/routers/users.py index 2d11218c2..a9f356c91 100644 --- a/backend/routers/users.py +++ b/backend/routers/users.py @@ -12,7 +12,7 @@ from models.other import Person, CreatePerson from models.users import WebhookType from utils.apps import get_available_app_by_id -from utils.llm import followup_question_prompt +from utils.llm.followup import followup_question_prompt from utils.other import endpoints as auth from utils.other.storage import delete_all_conversation_recordings, get_user_person_speech_samples, \ delete_user_person_speech_samples diff --git a/backend/scripts/rag/app.py b/backend/scripts/rag/app.py index 0663c13e6..967236926 100644 --- a/backend/scripts/rag/app.py +++ b/backend/scripts/rag/app.py @@ -21,7 +21,7 @@ from models.chat import Message from models.conversation import Conversation from models.transcript_segment import TranscriptSegment -from utils.llm import qa_rag +from utils.llm.chat import qa_rag from utils.retrieval.rag import retrieve_rag_context # File to store the state diff --git a/backend/scripts/rag/memories.py b/backend/scripts/rag/memories.py index 688b90596..eec26c098 100644 --- a/backend/scripts/rag/memories.py +++ b/backend/scripts/rag/memories.py @@ -1,5 +1,5 @@ import database.memories as memories_db -from utils.llm import new_memories_extractor +from utils.llm.memories import new_memories_extractor import threading from typing import Tuple diff --git a/backend/utils/app_integrations.py b/backend/utils/app_integrations.py index d0f8978b2..f00252105 100644 --- a/backend/utils/app_integrations.py +++ b/backend/utils/app_integrations.py @@ -16,10 +16,8 @@ from models.notification_message import NotificationMessage from utils.apps import get_available_apps from utils.notifications import send_notification -from utils.llm import ( - generate_embedding, - get_proactive_message -) +from utils.llm.clients import generate_embedding +from utils.llm.proactive_notification import get_proactive_message from database.vector_db import query_vectors_by_metadata import database.conversations as conversations_db diff --git a/backend/utils/apps.py b/backend/utils/apps.py index 5ed7bc5c5..25cc9a790 100644 --- a/backend/utils/apps.py +++ b/backend/utils/apps.py @@ -25,7 +25,7 @@ from models.app import App, UsageHistoryItem, UsageHistoryType from models.conversation import Conversation from utils import stripe -from utils.llm import condense_conversations, condense_memories, generate_persona_description, condense_tweets +from utils.llm.persona import condense_conversations, condense_memories, generate_persona_description, condense_tweets from utils.social import get_twitter_timeline, TwitterProfile, get_twitter_profile MarketplaceAppReviewUIDs = os.getenv('MARKETPLACE_APP_REVIEWERS').split(',') if os.getenv( diff --git a/backend/utils/conversations/memories.py b/backend/utils/conversations/memories.py index aaf61e475..0aaa2be0a 100644 --- a/backend/utils/conversations/memories.py +++ b/backend/utils/conversations/memories.py @@ -3,7 +3,7 @@ import database.memories as memories_db from models.memories import MemoryDB, Memory, CategoryEnum from models.integrations import ExternalIntegrationCreateMemory -from utils.llm import extract_memories_from_text +from utils.llm.memories import extract_memories_from_text def process_external_integration_memory(uid: str, memory_data: ExternalIntegrationCreateMemory, app_id: str) -> List[ diff --git a/backend/utils/conversations/process_conversation.py b/backend/utils/conversations/process_conversation.py index bddad7bc3..7b2db2eca 100644 --- a/backend/utils/conversations/process_conversation.py +++ b/backend/utils/conversations/process_conversation.py @@ -25,12 +25,16 @@ from models.trend import Trend from models.notification_message import NotificationMessage from utils.apps import get_available_apps, update_personas_async, sync_update_persona_prompt -from utils.llm import obtain_emotional_message, retrieve_metadata_fields_from_transcript, \ - summarize_open_glass, get_transcript_structure, generate_embedding, \ - get_app_result, should_discard_conversation, summarize_experience_text, new_memories_extractor, \ - trends_extractor, get_message_structure, \ - retrieve_metadata_from_message, retrieve_metadata_from_text, select_best_app_for_conversation, \ - extract_memories_from_text, get_reprocess_transcript_structure +from utils.llm.conversation_processing import get_transcript_structure, \ + get_app_result, should_discard_conversation, select_best_app_for_conversation, \ + get_reprocess_transcript_structure +from utils.llm.memories import extract_memories_from_text, new_memories_extractor +from utils.llm.external_integrations import summarize_experience_text +from utils.llm.openglass import summarize_open_glass +from utils.llm.trends import trends_extractor +from utils.llm.chat import retrieve_metadata_from_text, retrieve_metadata_from_message, retrieve_metadata_fields_from_transcript, obtain_emotional_message +from utils.llm.external_integrations import get_message_structure +from utils.llm.clients import generate_embedding from utils.notifications import send_notification from utils.other.hume import get_hume, HumeJobCallbackModel, HumeJobModelPredictionResponseModel from utils.retrieval.rag import retrieve_rag_conversation_context diff --git a/backend/utils/llm.py b/backend/utils/llm.py index 27302be88..4f1d936fb 100644 --- a/backend/utils/llm.py +++ b/backend/utils/llm.py @@ -67,308 +67,25 @@ def num_tokens_from_string(string: str) -> int: # ********************************************** # ********** CONVERSATION PROCESSING *********** # ********************************************** - -class DiscardConversation(BaseModel): - discard: bool = Field(description="If the conversation should be discarded or not") - - -class SpeakerIdMatch(BaseModel): - speaker_id: int = Field(description="The speaker id assigned to the segment") - - -def should_discard_conversation(transcript: str) -> bool: - if len(transcript.split(' ')) > 100: - return False - - parser = PydanticOutputParser(pydantic_object=DiscardConversation) - prompt = ChatPromptTemplate.from_messages([ - ''' - You will receive a transcript snippet. Length is never a reason to discard. - - Task - Decide if the snippet should be saved as a memory. - - KEEP → output: discard = False - DISCARD → output: discard = True - - KEEP (discard = False) if it contains any of the following: - • a task, request, or action item - • a decision, commitment, or plan - • a question that requires follow-up - • personal facts, preferences, or details likely useful later - • an insight, summary, or key takeaway - - If none of these are present, DISCARD (discard = True). - - Return exactly one line: - discard = - - - Transcript: ```{transcript}``` - - {format_instructions}'''.replace(' ', '').strip() - ]) - chain = prompt | llm_mini | parser - try: - response: DiscardConversation = chain.invoke({ - 'transcript': transcript.strip(), - 'format_instructions': parser.get_format_instructions(), - }) - return response.discard - - except Exception as e: - print(f'Error determining memory discard: {e}') - return False - - -def get_transcript_structure(transcript: str, started_at: datetime, language_code: str, tz: str) -> Structured: - prompt_text = '''You are an expert conversation analyzer. Your task is to analyze the conversation and provide structure and clarity to the recording transcription of a conversation. - The conversation language is {language_code}. Use the same language {language_code} for your response. - - For the title, use the main topic of the conversation. - For the overview, condense the conversation into a summary with the main topics discussed, make sure to capture the key points and important details from the conversation. - For the emoji, select a single emoji that vividly reflects the core subject, mood, or outcome of the conversation. Strive for an emoji that is specific and evocative, rather than generic (e.g., prefer 🎉 for a celebration over 👍 for general agreement, or 💡 for a new idea over 🧠 for general thought). - For the action items, include a list of commitments, specific tasks or actionable steps from the conversation that the user is planning to do or has to do on that specific day or in future. Remember the speaker is busy so this has to be very efficient and concise, otherwise they might miss some critical tasks. Specify which speaker is responsible for each action item. - For the category, classify the conversation into one of the available categories. - For Calendar Events, include a list of events extracted from the conversation, that the user must have on his calendar. For date context, this conversation happened on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. - - Transcript: ```{transcript}``` - - {format_instructions}'''.replace(' ', '').strip() - - prompt = ChatPromptTemplate.from_messages([('system', prompt_text)]) - chain = prompt | llm_mini | parser - - response = chain.invoke({ - 'transcript': transcript.strip(), - 'format_instructions': parser.get_format_instructions(), - 'language_code': language_code, - 'started_at': started_at.isoformat(), - 'tz': tz, - }) - - for event in (response.events or []): - if event.duration > 180: - event.duration = 180 - event.created = False - return response - - -def get_reprocess_transcript_structure(transcript: str, started_at: datetime, language_code: str, tz: str, - title: str) -> Structured: - prompt_text = '''You are an expert conversation analyzer. Your task is to analyze the conversation and provide structure and clarity to the recording transcription of a conversation. - The conversation language is {language_code}. Use the same language {language_code} for your response. - - For the title, use ```{title}```, if it is empty, use the main topic of the conversation. - For the overview, condense the conversation into a summary with the main topics discussed, make sure to capture the key points and important details from the conversation. - For the emoji, select a single emoji that vividly reflects the core subject, mood, or outcome of the conversation. Strive for an emoji that is specific and evocative, rather than generic (e.g., prefer 🎉 for a celebration over 👍 for general agreement, or 💡 for a new idea over 🧠 for general thought). - For the action items, include a list of commitments, specific tasks or actionable steps from the conversation that the user is planning to do or has to do on that specific day or in future. Remember the speaker is busy so this has to be very efficient and concise, otherwise they might miss some critical tasks. Specify which speaker is responsible for each action item. - For the category, classify the conversation into one of the available categories. - For Calendar Events, include a list of events extracted from the conversation, that the user must have on his calendar. For date context, this conversation happened on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. - - Transcript: ```{transcript}``` - - {format_instructions}'''.replace(' ', '').strip() - - prompt = ChatPromptTemplate.from_messages([('system', prompt_text)]) - chain = prompt | llm_mini | parser - - response = chain.invoke({ - 'transcript': transcript.strip(), - 'title': title, - 'format_instructions': parser.get_format_instructions(), - 'language_code': language_code, - 'started_at': started_at.isoformat(), - 'tz': tz, - }) - - for event in (response.events or []): - if event.duration > 180: - event.duration = 180 - event.created = False - return response - - -def get_app_result(transcript: str, app: App) -> str: - prompt = f''' - Your are an AI with the following characteristics: - Name: {app.name}, - Description: {app.description}, - Task: ${app.memory_prompt} - - Conversation: ```{transcript.strip()}```, - ''' - - response = llm_medium_experiment.invoke(prompt) - content = response.content.replace('```json', '').replace('```', '') - return content - - -def get_app_result_v1(transcript: str, app: App) -> str: - prompt = f''' - Your are an AI with the following characteristics: - Name: ${app.name}, - Description: ${app.description}, - Task: ${app.memory_prompt} - - Note: It is possible that the conversation you are given, has nothing to do with your task, \ - in that case, output an empty string. (For example, you are given a business conversation, but your task is medical analysis) - - Conversation: ```{transcript.strip()}```, - - Make sure to be concise and clear. - ''' - - response = llm_mini.invoke(prompt) - content = response.content.replace('```json', '').replace('```', '') - if len(content) < 5: - return '' - return content +# move to utils/llm/conversation_processing.py # ************************************** # ************* OPENGLASS ************** # ************************************** -def summarize_open_glass(photos: List[ConversationPhoto]) -> Structured: - photos_str = '' - for i, photo in enumerate(photos): - photos_str += f'{i + 1}. "{photo.description}"\n' - prompt = f'''The user took a series of pictures from his POV, generated a description for each photo, and wants to create a memory from them. - - For the title, use the main topic of the scenes. - For the overview, condense the descriptions into a brief summary with the main topics discussed, make sure to capture the key points and important details. - For the category, classify the scenes into one of the available categories. - - Photos Descriptions: ```{photos_str}``` - '''.replace(' ', '').strip() - return llm_mini.with_structured_output(Structured).invoke(prompt) +# move to utils/llm/openglass.py # ************************************************** # ************* EXTERNAL INTEGRATIONS ************** # ************************************************** - - -def get_message_structure(text: str, started_at: datetime, language_code: str, tz: str, - text_source_spec: str = None) -> Structured: - prompt_text = ''' - You are an expert message analyzer. Your task is to analyze the message content and provide structure and clarity. - The message language is {language_code}. Use the same language {language_code} for your response. - - For the title, create a concise title that captures the main topic of the message. - For the overview, summarize the message with the main points discussed, make sure to capture the key information and important details. - For the action items, include any tasks or actions that need to be taken based on the message. - For the category, classify the message into one of the available categories. - For Calendar Events, include any events or meetings mentioned in the message. For date context, this message was sent on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. - - Message Content: ```{text}``` - Message Source: {text_source_spec} - - {format_instructions}'''.replace(' ', '').strip() - - prompt = ChatPromptTemplate.from_messages([('system', prompt_text)]) - chain = prompt | llm_mini | parser - - response = chain.invoke({ - 'language_code': language_code, - 'started_at': started_at.isoformat(), - 'tz': tz, - 'text': text, - 'text_source_spec': text_source_spec if text_source_spec else 'Messaging App', - 'format_instructions': parser.get_format_instructions(), - }) - - for event in (response.events or []): - if event.duration > 180: - event.duration = 180 - event.created = False - return response - - -def summarize_experience_text(text: str, text_source_spec: str = None) -> Structured: - source_context = f"Source: {text_source_spec}" if text_source_spec else "their own experiences or thoughts" - prompt = f'''The user sent a text of {source_context}, and wants to create a memory from it. - For the title, use the main topic of the experience or thought. - For the overview, condense the descriptions into a brief summary with the main topics discussed, make sure to capture the key points and important details. - For the category, classify the scenes into one of the available categories. - For the action items, include any tasks or actions that need to be taken based on the content. - For Calendar Events, include any events or meetings mentioned in the content. - - Text: ```{text}``` - '''.replace(' ', '').strip() - return llm_mini.with_structured_output(Structured).invoke(prompt) - - -def get_conversation_summary(uid: str, memories: List[Conversation]) -> str: - user_name, memories_str = get_prompt_memories(uid) - - conversation_history = Conversation.conversations_to_string(memories) - - prompt = f""" - You are an experienced mentor, that helps people achieve their goals and improve their lives. - You are advising {user_name} right now, {memories_str} - - The following are a list of {user_name}'s conversations from today, with the transcripts and a slight summary of each, that {user_name} had during his day. - {user_name} wants to get a summary of the key action items {user_name} has to take based on today's conversations. - - Remember {user_name} is busy so this has to be very efficient and concise. - Respond in at most 50 words. - - Output your response in plain text, without markdown. No newline character and only use numbers for the action items. - ``` - ${conversation_history} - ``` - """.replace(' ', '').strip() - # print(prompt) - return llm_mini.invoke(prompt).content - - -def generate_embedding(content: str) -> List[float]: - return embeddings.embed_documents([content])[0] +# move to utils/llm/external_integrations.py # **************************************** # ************* CHAT BASICS ************** # **************************************** -def initial_chat_message(uid: str, plugin: Optional[App] = None, prev_messages_str: str = '') -> str: - user_name, memories_str = get_prompt_memories(uid) - if plugin is None: - prompt = f""" -You are 'Omi', a friendly and helpful assistant who aims to make {user_name}'s life better 10x. -You know the following about {user_name}: {memories_str}. - -{prev_messages_str} - -Compose {"an initial" if not prev_messages_str else "a follow-up"} message to {user_name} that fully embodies your friendly and helpful personality. Use warm and cheerful language, and include light humor if appropriate. The message should be short, engaging, and make {user_name} feel welcome. Do not mention that you are an assistant or that this is an initial message; just {"start" if not prev_messages_str else "continue"} the conversation naturally, showcasing your personality. -""" - else: - prompt = f""" -You are '{plugin.name}', {plugin.chat_prompt}. -You know the following about {user_name}: {memories_str}. - -{prev_messages_str} - -As {plugin.name}, fully embrace your personality and characteristics in your {"initial" if not prev_messages_str else "follow-up"} message to {user_name}. Use language, tone, and style that reflect your unique personality traits. {"Start" if not prev_messages_str else "Continue"} the conversation naturally with a short, engaging message that showcases your personality and humor, and connects with {user_name}. Do not mention that you are an AI or that this is an initial message. -""" - prompt = prompt.strip() - return llm_mini.invoke(prompt).content - - -def initial_persona_chat_message(uid: str, app: Optional[App] = None, messages: List[Message] = []) -> str: - print("initial_persona_chat_message") - chat_messages = [SystemMessage(content=app.persona_prompt)] - for msg in messages: - if msg.sender == MessageSender.ai: - chat_messages.append(AIMessage(content=msg.text)) - else: - chat_messages.append(HumanMessage(content=msg.text)) - chat_messages.append(HumanMessage( - content='lets begin. you write the first message, one short provocative question relevant to your identity. never respond with **. while continuing the convo, always respond w short msgs, lowercase.')) - llm_call = llm_persona_mini_stream - if app.is_influencer: - llm_call = llm_persona_medium_stream - return llm_call.invoke(chat_messages).content # ********************************************* @@ -376,1310 +93,63 @@ def initial_persona_chat_message(uid: str, app: Optional[App] = None, messages: # ********************************************* -class RequiresContext(BaseModel): - value: bool = Field(description="Based on the conversation, this tells if context is needed to respond") - - -class TopicsContext(BaseModel): - topics: List[CategoryEnum] = Field(default=[], description="List of topics.") - - -class DatesContext(BaseModel): - dates_range: List[datetime] = Field(default=[], - examples=[['2024-12-23T00:00:00+07:00', '2024-12-23T23:59:00+07:00']], - description="Dates range. (Optional)", ) - - -def requires_context(question: str) -> bool: - prompt = f''' - Based on the current question your task is to determine whether the user is asking a question that requires context outside the conversation to be answered. - Take as example: if the user is saying "Hi", "Hello", "How are you?", "Good morning", etc, the answer is False. - - User's Question: - {question} - ''' - with_parser = llm_mini.with_structured_output(RequiresContext) - response: RequiresContext = with_parser.invoke(prompt) - try: - return response.value - except ValidationError: - return False - - -class IsAnOmiQuestion(BaseModel): - value: bool = Field(description="If the message is an Omi/Friend related question") - - -def retrieve_is_an_omi_question(question: str) -> bool: - prompt = f''' - Task: Analyze the question to identify if the user is inquiring about the functionalities or usage of the app, Omi or Friend. Focus on detecting questions related to the app's operations or capabilities. - - Examples of User Questions: - - - "How does it work?" - - "What can you do?" - - "How can I buy it?" - - "Where do I get it?" - - "How does the chat function?" - - Instructions: - - 1. Review the question carefully. - 2. Determine if the user is asking about: - - The operational aspects of the app. - - How to utilize the app effectively. - - Any specific features or purchasing options. - - Output: Clearly state if the user is asking a question related to the app's functionality or usage. If yes, specify the nature of the inquiry. - - User's Question: - {question} - '''.replace(' ', '').strip() - with_parser = llm_mini.with_structured_output(IsAnOmiQuestion) - response: IsAnOmiQuestion = with_parser.invoke(prompt) - try: - return response.value - except ValidationError: - return False - - -class IsFileQuestion(BaseModel): - value: bool = Field(description="If the message is related to file/image") - - -def retrieve_is_file_question(question: str) -> bool: - prompt = f''' - Based on the current question, your task is to determine whether the user is referring to a file or an image that was just attached or mentioned earlier in the conversation. - - Examples where the answer is True: - - "Can you process this file?" - - "What do you think about the image I uploaded?" - - "Can you extract text from the document?" - - Examples where the answer is False: - - "How is the weather today?" - - "Tell me a joke." - - "What is the capital of France?" - - User's Question: - {question} - ''' - - with_parser = llm_mini.with_structured_output(IsFileQuestion) - response: IsFileQuestion = with_parser.invoke(prompt) - try: - return response.value - except ValidationError: - return False - - -def retrieve_context_dates_by_question(question: str, tz: str) -> List[datetime]: - prompt = f''' - You MUST determine the appropriate date range in {tz} that provides context for answering the provided. - - If the does not reference a date or a date range, respond with an empty list: [] - - Current date time in UTC: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} - - - {question} - - - '''.replace(' ', '').strip() - - # print(prompt) - # print(llm_mini.invoke(prompt).content) - with_parser = llm_mini.with_structured_output(DatesContext) - response: DatesContext = with_parser.invoke(prompt) - return response.dates_range - - -class SummaryOutput(BaseModel): - summary: str = Field(description="The extracted content, maximum 500 words.") - - -def chunk_extraction(segments: List[TranscriptSegment], topics: List[str]) -> str: - content = TranscriptSegment.segments_as_string(segments) - prompt = f''' - You are an experienced detective, your task is to extract the key points of the conversation related to the topics you were provided. - You will be given a conversation transcript of a low quality recording, and a list of topics. - - Include the most relevant information about the topics, people mentioned, events, locations, facts, phrases, and any other relevant information. - It is possible that the conversation doesn't have anything related to the topics, in that case, output an empty string. - - Conversation: - {content} - - Topics: {topics} - ''' - with_parser = llm_mini.with_structured_output(SummaryOutput) - response: SummaryOutput = with_parser.invoke(prompt) - return response.summary - - -def _get_answer_simple_message_prompt(uid: str, messages: List[Message], app: Optional[App] = None) -> str: - conversation_history = Message.get_messages_as_string( - messages, use_user_name_if_available=True, use_plugin_name_if_available=True - ) - user_name, memories_str = get_prompt_memories(uid) - - plugin_info = "" - if app: - plugin_info = f"Your name is: {app.name}, and your personality/description is '{app.description}'.\nMake sure to reflect your personality in your response.\n" - - return f""" - You are an assistant for engaging personal conversations. - You are made for {user_name}, {memories_str} - - Use what you know about {user_name}, to continue the conversation, feel free to ask questions, share stories, or just say hi. - {plugin_info} - - Conversation History: - {conversation_history} - - Answer: - """.replace(' ', '').strip() - - -def answer_simple_message(uid: str, messages: List[Message], plugin: Optional[App] = None) -> str: - prompt = _get_answer_simple_message_prompt(uid, messages, plugin) - return llm_mini.invoke(prompt).content - - -def answer_simple_message_stream(uid: str, messages: List[Message], plugin: Optional[App] = None, - callbacks=[]) -> str: - prompt = _get_answer_simple_message_prompt(uid, messages, plugin) - return llm_mini_stream.invoke(prompt, {'callbacks': callbacks}).content - - -def _get_answer_omi_question_prompt(messages: List[Message], context: str) -> str: - conversation_history = Message.get_messages_as_string( - messages, use_user_name_if_available=True, use_plugin_name_if_available=True - ) - - return f""" - You are an assistant for answering questions about the app Omi, also known as Friend. - Continue the conversation, answering the question based on the context provided. - - Context: - ``` - {context} - ``` - - Conversation History: - {conversation_history} - - Answer: - """.replace(' ', '').strip() - - -def answer_omi_question(messages: List[Message], context: str) -> str: - prompt = _get_answer_omi_question_prompt(messages, context) - return llm_mini.invoke(prompt).content - - -def answer_omi_question_stream(messages: List[Message], context: str, callbacks: []) -> str: - prompt = _get_answer_omi_question_prompt(messages, context) - return llm_mini_stream.invoke(prompt, {'callbacks': callbacks}).content - - -def answer_persona_question_stream(app: App, messages: List[Message], callbacks: []) -> str: - print("answer_persona_question_stream") - chat_messages = [SystemMessage(content=app.persona_prompt)] - for msg in messages: - if msg.sender == MessageSender.ai: - chat_messages.append(AIMessage(content=msg.text)) - else: - chat_messages.append(HumanMessage(content=msg.text)) - llm_call = llm_persona_mini_stream - if app.is_influencer: - llm_call = llm_persona_medium_stream - return llm_call.invoke(chat_messages, {'callbacks': callbacks}).content - - -def _get_qa_rag_prompt(uid: str, question: str, context: str, plugin: Optional[App] = None, - cited: Optional[bool] = False, - messages: List[Message] = [], tz: Optional[str] = "UTC") -> str: - user_name, memories_str = get_prompt_memories(uid) - memories_str = '\n'.join(memories_str.split('\n')[1:]).strip() - - # Use as template (make sure it varies every time): "If I were you $user_name I would do x, y, z." - context = context.replace('\n\n', '\n').strip() - plugin_info = "" - if plugin: - plugin_info = f"Your name is: {plugin.name}, and your personality/description is '{plugin.description}'.\nMake sure to reflect your personality in your response.\n" - - # Ref: https://www.reddit.com/r/perplexity_ai/comments/1hi981d - cited_instruction = """ - - You MUST cite the most relevant that answer the question. \ - - Only cite in not , not . - - Cite in memories using [index] at the end of sentences when needed, for example "You discussed optimizing firmware with your teammate yesterday[1][2]". - - NO SPACE between the last word and the citation. - - Avoid citing irrelevant memories. - """ - - return f""" - - You are an assistant for question-answering tasks. - - - - Write an accurate, detailed, and comprehensive response to the in the most personalized way possible, using the , provided. - - - - - Refine the based on the last before answering it. - - DO NOT use the AI's message from as references to answer the - - Use and to refer to the time context of the - - It is EXTREMELY IMPORTANT to directly answer the question, keep the answer concise and high-quality. - - NEVER say "based on the available memories". Get straight to the point. - - If you don't know the answer or the premise is incorrect, explain why. If the are empty or unhelpful, answer the question as well as you can with existing knowledge. - - You MUST follow the if the user is asking for reporting or summarizing their dates, weeks, months, or years. - {cited_instruction if cited and len(context) > 0 else ""} - {"- Regard the " if len(plugin_info) > 0 else ""}. - - - - {plugin_info} - - - - - Answer with the template: - - Goals and Achievements - - Mood Tracker - - Gratitude Log - - Lessons Learned - - - - {question} - - - - {context} - - - - {Message.get_messages_as_xml(messages)} - - - - [Use the following User Facts if relevant to the ] - {memories_str.strip()} - - - - Current date time in UTC: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} - - - - Question's timezone: {tz} - - - - """.replace(' ', '').replace('\n\n\n', '\n\n').strip() - - -def qa_rag(uid: str, question: str, context: str, plugin: Optional[App] = None, cited: Optional[bool] = False, - messages: List[Message] = [], tz: Optional[str] = "UTC") -> str: - prompt = _get_qa_rag_prompt(uid, question, context, plugin, cited, messages, tz) - # print('qa_rag prompt', prompt) - return llm_medium.invoke(prompt).content - - -def qa_rag_stream(uid: str, question: str, context: str, plugin: Optional[App] = None, cited: Optional[bool] = False, - messages: List[Message] = [], tz: Optional[str] = "UTC", callbacks=[]) -> str: - prompt = _get_qa_rag_prompt(uid, question, context, plugin, cited, messages, tz) - # print('qa_rag prompt', prompt) - return llm_medium_stream.invoke(prompt, {'callbacks': callbacks}).content - - # ************************************************** # ************* RETRIEVAL (EMOTIONAL) ************** # ************************************************** -def retrieve_memory_context_params(memory: Conversation) -> List[str]: - transcript = memory.get_transcript(False) - if len(transcript) == 0: - return [] - - prompt = f''' - Based on the current transcript of a conversation. - - Your task is to extract the correct and most accurate context in the conversation, to be used to retrieve more information. - Provide a list of topics in which the current conversation needs context about, in order to answer the most recent user request. - - Conversation: - {transcript} - '''.replace(' ', '').strip() - - try: - with_parser = llm_mini.with_structured_output(TopicsContext) - response: TopicsContext = with_parser.invoke(prompt) - return response.topics - except Exception as e: - print(f'Error determining memory discard: {e}') - return [] - - -def obtain_emotional_message(uid: str, memory: Conversation, context: str, emotion: str) -> str: - user_name, memories_str = get_prompt_memories(uid) - transcript = memory.get_transcript(False) - prompt = f""" - You are a thoughtful and encouraging Friend. - Your best friend is {user_name}, {memories_str} - - {user_name} just finished a conversation where {user_name} experienced {emotion}. - - You will be given the conversation transcript, and context from previous related conversations of {user_name}. - - Remember, {user_name} is feeling {emotion}. - Use what you know about {user_name}, the transcript, and the related context, to help {user_name} overcome this feeling \ - (if bad), or celebrate (if good), by giving advice, encouragement, support, or suggesting the best action to take. - - Make sure the message is nice and short, no more than 20 words. - - Conversation Transcript: - {transcript} - - Context: - ``` - {context} - ``` - """.replace(' ', '').strip() - return llm_mini.invoke(prompt).content +# moved to utils/llm/chat.py # ********************************************* # ************* MEMORIES (FACTS) ************** # ********************************************* -class Memories(BaseModel): - facts: List[Memory] = Field( - min_items=0, - max_items=3, - description="List of **new** facts. If any", - default=[], - ) - - -class MemoriesByTexts(BaseModel): - facts: List[Memory] = Field( - description="List of **new** facts. If any", - default=[], - ) - - -def new_memories_extractor( - uid: str, segments: List[TranscriptSegment], user_name: Optional[str] = None, memories_str: Optional[str] = None -) -> List[Memory]: - # print('new_memories_extractor', uid, 'segments', len(segments), user_name, 'len(memories_str)', len(memories_str)) - if user_name is None or memories_str is None: - user_name, memories_str = get_prompt_memories(uid) - - content = TranscriptSegment.segments_as_string(segments, user_name=user_name) - if not content or len(content) < 25: # less than 5 words, probably nothing - return [] - # TODO: later, focus a lot on user said things, rn is hard because of speech profile accuracy - # TODO: include negative facts too? Things the user doesn't like? - # TODO: make it more strict? - - try: - parser = PydanticOutputParser(pydantic_object=Memories) - chain = extract_memories_prompt | llm_mini | parser - # with_parser = llm_mini.with_structured_output(Facts) - response: Memories = chain.invoke({ - 'user_name': user_name, - 'conversation': content, - 'memories_str': memories_str, - 'format_instructions': parser.get_format_instructions(), - }) - # for fact in response: - # fact.content = fact.content.replace(user_name, '').replace('The User', '').replace('User', '').strip() - return response.facts - except Exception as e: - print(f'Error extracting new facts: {e}') - return [] - - -def extract_memories_from_text( - uid: str, text: str, text_source: str, user_name: Optional[str] = None, memories_str: Optional[str] = None -) -> List[Memory]: - """Extract memories from external integration text sources like email, posts, messages""" - if user_name is None or memories_str is None: - user_name, memories_str = get_prompt_memories(uid) - - if not text or len(text) == 0: - return [] - - try: - parser = PydanticOutputParser(pydantic_object=MemoriesByTexts) - chain = extract_memories_text_content_prompt | llm_mini | parser - response: Memories = chain.invoke({ - 'user_name': user_name, - 'text_content': text, - 'text_source': text_source, - 'memories_str': memories_str, - 'format_instructions': parser.get_format_instructions(), - }) - return response.facts - except Exception as e: - print(f'Error extracting facts from {text_source}: {e}') - return [] - - -class Learnings(BaseModel): - result: List[str] = Field( - min_items=0, - max_items=2, - description="List of **new** learnings. If any", - default=[], - ) - - -def new_learnings_extractor( - uid: str, segments: List[TranscriptSegment], user_name: Optional[str] = None, - learnings_str: Optional[str] = None -) -> List[Memory]: - if user_name is None or learnings_str is None: - user_name, memories_str = get_prompt_memories(uid) - - content = TranscriptSegment.segments_as_string(segments, user_name=user_name) - if not content or len(content) < 100: - return [] - - try: - parser = PydanticOutputParser(pydantic_object=Learnings) - chain = extract_learnings_prompt | llm_mini | parser - response: Learnings = chain.invoke({ - 'user_name': user_name, - 'conversation': content, - 'learnings_str': learnings_str, - 'format_instructions': parser.get_format_instructions(), - }) - return list(map(lambda x: Memory(content=x, category=MemoryCategory.learnings), response.result)) - except Exception as e: - print(f'Error extracting new facts: {e}') - return [] - # ********************************** # ************* TRENDS ************** # ********************************** - - -class Item(BaseModel): - category: TrendEnum = Field(description="The category identified") - type: TrendType = Field(description="The sentiment identified") - topic: str = Field(description="The specific topic corresponding the category") - - -class ExpectedOutput(BaseModel): - items: List[Item] = Field(default=[], description="List of items.") - - -def trends_extractor(memory: Conversation) -> List[Item]: - transcript = memory.get_transcript(False) - if len(transcript) == 0: - return [] - - prompt = f''' - You will be given a finished conversation transcript. - You are responsible for extracting the topics of the conversation and classifying each one within one the following categories: {str([e.value for e in TrendEnum]).strip("[]")}. - You must identify if the perception is positive or negative, and classify it as "best" or "worst". - - For the specific topics here are the options available, you must classify the topic within one of these options: - - ceo_options: {", ".join(ceo_options)} - - company_options: {", ".join(company_options)} - - software_product_options: {", ".join(software_product_options)} - - hardware_product_options: {", ".join(hardware_product_options)} - - ai_product_options: {", ".join(ai_product_options)} - - For example, - If you identify the topic "Tesla stock has been going up incredibly", you should output: - - Category: company - - Type: best - - Topic: Tesla - - Conversation: - {transcript} - '''.replace(' ', '').strip() - try: - with_parser = llm_mini.with_structured_output(ExpectedOutput) - response: ExpectedOutput = with_parser.invoke(prompt) - filtered = [] - for item in response.items: - if item.topic not in [e for e in ( - ceo_options + company_options + software_product_options + hardware_product_options + ai_product_options)]: - continue - filtered.append(item) - return filtered - - except Exception as e: - print(f'Error determining memory discard: {e}') - return [] +# moved to utils/llm/trends.py # ********************************************************** # ************* RANDOM JOAN SPECIFIC FEATURES ************** # ********************************************************** - - -def followup_question_prompt(segments: List[TranscriptSegment]): - transcript_str = TranscriptSegment.segments_as_string(segments, include_timestamps=False) - words = transcript_str.split() - w_count = len(words) - if w_count < 10: - return '' - elif w_count > 100: - # trim to last 500 words - transcript_str = ' '.join(words[-100:]) - - prompt = f""" - You will be given the transcript of an in-progress conversation. - Your task as an engaging, fun, and curious conversationalist, is to suggest the next follow-up question to keep the conversation engaging. - - Conversation Transcript: - {transcript_str} - - Output your response in plain text, without markdown. - Output only the question, without context, be concise and straight to the point. - """.replace(' ', '').strip() - return llm_mini.invoke(prompt).content +# moved to utils/llm/followup.py # ********************************************** # ************* CHAT V2 LANGGRAPH ************** # ********************************************** - -class ExtractedInformation(BaseModel): - people: List[str] = Field( - default=[], - examples=[['John Doe', 'Jane Doe']], - description='Identify all the people names who were mentioned during the conversation.' - ) - topics: List[str] = Field( - default=[], - examples=[['Artificial Intelligence', 'Machine Learning']], - description='List all the main topics and subtopics that were discussed.', - ) - entities: List[str] = Field( - default=[], - examples=[['OpenAI', 'GPT-4']], - description='List any products, technologies, places, or other entities that are relevant to the conversation.' - ) - dates: List[str] = Field( - default=[], - examples=[['2024-01-01', '2024-01-02']], - description=f'Extract any dates mentioned in the conversation. Use the format YYYY-MM-DD.' - ) - - -class FiltersToUse(BaseModel): - people: List[str] = Field(default=[], description='People, names that could be relevant') - topics: List[str] = Field(default=[], description='Topics and subtopics that can help finding more information') - entities: List[str] = Field( - default=[], description='products, technologies, places, or other entities that could be relevant.' - ) - - -class OutputQuestion(BaseModel): - question: str = Field(description='The extracted user question from the conversation.') - - -class BestAppSelection(BaseModel): - app_id: str = Field( - description='The ID of the best app for processing this conversation, or an empty string if none are suitable.') - - -def select_best_app_for_conversation(conversation: Conversation, apps: List[App]) -> Optional[App]: - """ - Select the best app for the given conversation based on its structured content - and the specific task/outcome each app provides. - """ - if not apps: - return None - - if not conversation.structured: - return None - - structured_data = conversation.structured - conversation_details = f""" - Title: {structured_data.title or 'N/A'} - Category: {structured_data.category.value if structured_data.category else 'N/A'} - Overview: {structured_data.overview or 'N/A'} - Action Items: {ActionItem.actions_to_string(structured_data.action_items) if structured_data.action_items else 'None'} - Events Mentioned: {Event.events_to_string(structured_data.events) if structured_data.events else 'None'} - """ - - apps_xml = "\n" - for app in apps: - apps_xml += f""" - {app.id} - {app.name} - {app.description} - \n""" - apps_xml += "" - - prompt = f""" - You are an expert app selector. Your goal is to determine if any available app is genuinely suitable for processing the given conversation details based on the app's specific task and the potential value of its outcome. - - - {conversation_details.strip()} - - - - {apps_xml.strip()} - - - Task: - 1. Analyze the conversation's content, themes, action items, and events provided in ``. - 2. For each app in ``, evaluate its specific `` and ``. - 3. Determine if applying an app's `` to this specific conversation would produce a meaningful, relevant, and valuable outcome. - 4. Select the single best app whose task aligns most strongly with the conversation content and provides the most useful potential outcome. - - Critical Instructions: - - Only select an app if its specific task is highly relevant to the conversation's topics and details. A generic match based on description alone is NOT sufficient. - - Consider the *potential outcome* of applying the app's task. Would the result be insightful given this conversation? - - If no app's task strongly aligns with the conversation content or offers a valuable potential outcome (e.g., a business conversation when all apps are for medical analysis), you MUST return an empty `app_id`. - - Do not force a match. It is better to return an empty `app_id` than to select an inappropriate app. - - Provide ONLY the `app_id` of the best matching app, or an empty string if no app is suitable. - """ - - try: - with_parser = llm_mini.with_structured_output(BestAppSelection) - response: BestAppSelection = with_parser.invoke(prompt) - selected_app_id = response.app_id - - if not selected_app_id or selected_app_id.strip() == "": - return None - - # Find the app object with the matching ID - selected_app = next((app for app in apps if app.id == selected_app_id), None) - if selected_app: - return selected_app - else: - return None - - except Exception as e: - print(f"Error selecting best app: {e}") - return None - - -def extract_question_from_conversation(messages: List[Message]) -> str: - # user last messages - print("extract_question_from_conversation") - user_message_idx = len(messages) - for i in range(len(messages) - 1, -1, -1): - if messages[i].sender == MessageSender.ai: - break - if messages[i].sender == MessageSender.human: - user_message_idx = i - user_last_messages = messages[user_message_idx:] - if len(user_last_messages) == 0: - return "" - - prompt = f''' - You will be given a recent conversation between a and an . \ - The conversation may include a few messages exchanged in and partly build up the proper question. \ - Your task is to understand the and identify the question or follow-up question the user is asking. - - You will be provided with between you and the user to help you indentify the question. - - First, determine whether the user is asking a question or a follow-up question. \ - If the user is not asking a question or does not want to follow up, respond with an empty message. \ - For example, if the user says "Hi", "Hello", "How are you?", or "Good morning", the answer should be empty. - - If the contain a complete question, maintain the original version as accurately as possible. \ - Avoid adding unnecessary words. - - You MUST keep the original - - Output a WH-question, that is, a question that starts with a WH-word, like "What", "When", "Where", "Who", "Why", "How". - - Example 1: - - - User - - According to WHOOP, my HRV this Sunday was the highest it's been in a month. Here's what I did: - - Attended an outdoor party (cold weather, talked a lot more than usual). - Smoked weed (unusual for me). - Drank lots of relaxing tea. - - Can you prioritize each activity on a 0-10 scale for how much it might have influenced my HRV? - - - - Expected output: "How should each activity (going to a party and talking a lot, smoking weed, and drinking lots of relaxing tea) be prioritized on a scale of 0-10 in terms of their impact on my HRV, considering the recent activities that led to the highest HRV this month?" - - - {Message.get_messages_as_xml(user_last_messages)} - - - - {Message.get_messages_as_xml(messages)} - - - - - today - - my day - - my week - - this week - - this day - - etc. - - '''.replace(' ', '').strip() - # print(prompt) - question = llm_mini.with_structured_output(OutputQuestion).invoke(prompt).question - # print(question) - return question - - -def retrieve_metadata_fields_from_transcript( - uid: str, created_at: datetime, transcript_segment: List[dict], tz: str -) -> ExtractedInformation: - transcript = '' - for segment in transcript_segment: - transcript += f'{segment["text"].strip()}\n\n' - - # TODO: ask it to use max 2 words? to have more standardization possibilities - prompt = f''' - You will be given the raw transcript of a conversation, this transcript has about 20% word error rate, - and diarization is also made very poorly. - - Your task is to extract the most accurate information from the conversation in the output object indicated below. - - Make sure as a first step, you infer and fix the raw transcript errors and then proceed to extract the information. - - For context when extracting dates, today is {created_at.astimezone(timezone.utc).strftime('%Y-%m-%d')} in UTC. {tz} is the user's timezone, convert it to UTC and respond in UTC. - If one says "today", it means the current day. - If one says "tomorrow", it means the next day after today. - If one says "yesterday", it means the day before today. - If one says "next week", it means the next monday. - Do not include dates greater than 2025. - - Conversation Transcript: - ``` - {transcript} - ``` - '''.replace(' ', '') - try: - result: ExtractedInformation = llm_mini.with_structured_output(ExtractedInformation).invoke(prompt) - except Exception as e: - print('e', e) - return {'people': [], 'topics': [], 'entities': [], 'dates': []} - - def normalize_filter(value: str) -> str: - # Convert to lowercase and strip whitespace - value = value.lower().strip() - - # Remove special characters and extra spaces - value = re.sub(r'[^\w\s-]', '', value) - value = re.sub(r'\s+', ' ', value) - - # Remove common filler words - filler_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to'} - value = ' '.join(word for word in value.split() if word not in filler_words) - - # Standardize common variations - value = value.replace('artificial intelligence', 'ai') - value = value.replace('machine learning', 'ml') - value = value.replace('natural language processing', 'nlp') - - return value.strip() - - metadata = { - 'people': [normalize_filter(p) for p in result.people], - 'topics': [normalize_filter(t) for t in result.topics], - 'entities': [normalize_filter(e) for e in result.topics], - 'dates': [] - } - # 'dates': [date.strftime('%Y-%m-%d') for date in result.dates], - for date in result.dates: - try: - date = datetime.strptime(date, '%Y-%m-%d') - if date.year > 2025: - continue - metadata['dates'].append(date.strftime('%Y-%m-%d')) - except Exception as e: - print(f'Error parsing date: {e}') - - for p in metadata['people']: - add_filter_category_item(uid, 'people', p) - for t in metadata['topics']: - add_filter_category_item(uid, 'topics', t) - for e in metadata['entities']: - add_filter_category_item(uid, 'entities', e) - for d in metadata['dates']: - add_filter_category_item(uid, 'dates', d) - - return metadata - - -def retrieve_metadata_from_message(uid: str, created_at: datetime, message_text: str, tz: str, - source_spec: str = None) -> ExtractedInformation: - """Extract metadata from messaging app content""" - source_context = f"from {source_spec}" if source_spec else "from a messaging application" - - prompt = f''' - You will be given the content of a message or conversation {source_context}. - - Your task is to extract the most accurate information from the message in the output object indicated below. - - Focus on identifying: - 1. People mentioned in the message (sender, recipients, and anyone referenced) - 2. Topics discussed in the message - 3. Organizations, products, locations, or other entities mentioned - 4. Any dates or time references - - For context when extracting dates, today is {created_at.astimezone(timezone.utc).strftime('%Y-%m-%d')} in UTC. - {tz} is the user's timezone, convert it to UTC and respond in UTC. - If the message mentions "today", it means the current day. - If the message mentions "tomorrow", it means the next day after today. - If the message mentions "yesterday", it means the day before today. - If the message mentions "next week", it means the next monday. - Do not include dates greater than 2025. - - Message Content: - ``` - {message_text} - ``` - '''.replace(' ', '') - - return _process_extracted_metadata(uid, prompt) - - -def retrieve_metadata_from_text(uid: str, created_at: datetime, text: str, tz: str, - source_spec: str = None) -> ExtractedInformation: - """Extract metadata from generic text content""" - source_context = f"from {source_spec}" if source_spec else "from a text document" - - prompt = f''' - You will be given the content of a text {source_context}. - - Your task is to extract the most accurate information from the text in the output object indicated below. - - Focus on identifying: - 1. People mentioned in the text (author, recipients, and anyone referenced) - 2. Topics discussed in the text - 3. Organizations, products, locations, or other entities mentioned - 4. Any dates or time references - - For context when extracting dates, today is {created_at.astimezone(timezone.utc).strftime('%Y-%m-%d')} in UTC. - {tz} is the user's timezone, convert it to UTC and respond in UTC. - If the text mentions "today", it means the current day. - If the text mentions "tomorrow", it means the next day after today. - If the text mentions "yesterday", it means the day before today. - If the text mentions "next week", it means the next monday. - Do not include dates greater than 2025. - - Text Content: - ``` - {text} - ``` - '''.replace(' ', '') - - return _process_extracted_metadata(uid, prompt) - - -def _process_extracted_metadata(uid: str, prompt: str) -> dict: - """Process the extracted metadata from any source""" - try: - result: ExtractedInformation = llm_mini.with_structured_output(ExtractedInformation).invoke(prompt) - except Exception as e: - print(f'Error extracting metadata: {e}') - return {'people': [], 'topics': [], 'entities': [], 'dates': []} - - def normalize_filter(value: str) -> str: - # Convert to lowercase and strip whitespace - value = value.lower().strip() - - # Remove special characters and extra spaces - value = re.sub(r'[^\w\s-]', '', value) - value = re.sub(r'\s+', ' ', value) - - # Remove common filler words - filler_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to'} - value = ' '.join(word for word in value.split() if word not in filler_words) - - # Standardize common variations - value = value.replace('artificial intelligence', 'ai') - value = value.replace('machine learning', 'ml') - value = value.replace('natural language processing', 'nlp') - - return value.strip() - - metadata = { - 'people': [normalize_filter(p) for p in result.people], - 'topics': [normalize_filter(t) for t in result.topics], - 'entities': [normalize_filter(e) for e in result.entities], - 'dates': [] - } - - for date in result.dates: - try: - date = datetime.strptime(date, '%Y-%m-%d') - if date.year > 2025: - continue - metadata['dates'].append(date.strftime('%Y-%m-%d')) - except Exception as e: - print(f'Error parsing date: {e}') - - for p in metadata['people']: - add_filter_category_item(uid, 'people', p) - for t in metadata['topics']: - add_filter_category_item(uid, 'topics', t) - for e in metadata['entities']: - add_filter_category_item(uid, 'entities', e) - for d in metadata['dates']: - add_filter_category_item(uid, 'dates', d) - - return metadata - - -def select_structured_filters(question: str, filters_available: dict) -> dict: - prompt = f''' - Based on a question asked by the user to an AI, the AI needs to search for the user information related to topics, entities, people, and dates that will help it answering. - Your task is to identify the correct fields that can be related to the question and can help answering. - - You must choose for each field, only the ones available in the JSON below. - Find as many as possible that can relate to the question asked. - ``` - {json.dumps(filters_available, indent=2)} - ``` - - Question: {question} - '''.replace(' ', '').strip() - # print(prompt) - with_parser = llm_mini.with_structured_output(FiltersToUse) - try: - response: FiltersToUse = with_parser.invoke(prompt) - # print('select_structured_filters:', response.dict()) - response.topics = [t for t in response.topics if t in filters_available['topics']] - response.people = [p for p in response.people if p in filters_available['people']] - response.entities = [e for e in response.entities if e in filters_available['entities']] - return response.dict() - except ValidationError: - return {} +# moved to utils/llm/chat.py # ************************************************** # ************* REALTIME V2 LANGGRAPH ************** # ************************************************** - - -def extract_question_from_transcript(uid: str, segments: List[TranscriptSegment]) -> str: - user_name, memories_str = get_prompt_memories(uid) - prompt = f''' - {user_name} is having a conversation. - - This is what you know about {user_name}: {memories_str} - - You will be the transcript of a recent conversation between {user_name} and a few people, \ - your task is to understand the last few exchanges, and identify in order to provide advice to {user_name}, what other things about {user_name} \ - you should know. - - For example, if the conversation is about a new job, you should output a question like "What discussions have I had about job search?". - For example, if the conversation is about a new programming languages, you should output a question like "What have I chatted about programming?". - - Make sure as a first step, you infer and fix the raw transcript errors and then proceed to figure out the most meaningful question to ask. - - You must output at WH-question, that is, a question that starts with a WH-word, like "What", "When", "Where", "Who", "Why", "How". - - Conversation: - ``` - {TranscriptSegment.segments_as_string(segments)} - ``` - '''.replace(' ', '').strip() - return llm_mini.with_structured_output(OutputQuestion).invoke(prompt).question - - -class OutputMessage(BaseModel): - message: str = Field(description='The message to be sent to the user.', max_length=200) - - -def provide_advice_message(uid: str, segments: List[TranscriptSegment], context: str) -> str: - user_name, memories_str = get_prompt_memories(uid) - transcript = TranscriptSegment.segments_as_string(segments) - # TODO: tweak with different type of requests, like this, or roast, or praise or emotional, etc. - - prompt = f""" - You are a brutally honest, very creative, sometimes funny, indefatigable personal life coach who helps people improve their own agency in life, \ - pulling in pop culture references and inspirational business and life figures from recent history, mixed in with references to recent personal memories, - to help drive the point across. - - {memories_str} - - {user_name} just had a conversation and is asking for advice on what to do next. - - In order to answer you must analyize: - - The conversation transcript. - - The related conversations from previous days. - - The facts you know about {user_name}. - - You start all your sentences with: - - "If I were you, I would do this..." - - "I think you should do x..." - - "I believe you need to do y..." - - Your sentences are short, to the point, and very direct, at most 20 words. - MUST OUTPUT 20 words or less. - - Conversation Transcript: - {transcript} - - Context: - ``` - {context} - ``` - """.replace(' ', '').strip() - return llm_mini.with_structured_output(OutputMessage).invoke(prompt).message +# moved to utils/llm/chat.py # ************************************************** -# ************* PROACTIVE NOTIFICATION PLUGIN ************** +# ************* PROACTIVE NOTIFICATION ************* # ************************************************** - -def get_proactive_message(uid: str, plugin_prompt: str, params: [str], context: str, - chat_messages: List[Message]) -> str: - user_name, memories_str = get_prompt_memories(uid) - - prompt = plugin_prompt - for param in params: - if param == "user_name": - prompt = prompt.replace("{{user_name}}", user_name) - continue - if param == "user_facts": - prompt = prompt.replace("{{user_facts}}", memories_str) - continue - if param == "user_context": - prompt = prompt.replace("{{user_context}}", context if context else "") - continue - if param == "user_chat": - prompt = prompt.replace("{{user_chat}}", - Message.get_messages_as_string(chat_messages) if chat_messages else "") - continue - prompt = prompt.replace(' ', '').strip() - # print(prompt) - - return llm_mini.invoke(prompt).content +# moved to utils/llm/proactive_notification.py # ************************************************** # *************** APPS AI GENERATE ***************** # ************************************************** -def generate_description(app_name: str, description: str) -> str: - prompt = f""" - You are an AI assistant specializing in crafting detailed and engaging descriptions for apps. - You will be provided with the app's name and a brief description which might not be that good. Your task is to expand on the given information, creating a captivating and detailed app description that highlights the app's features, functionality, and benefits. - The description should be concise, professional, and not more than 40 words, ensuring clarity and appeal. Respond with only the description, tailored to the app's concept and purpose. - App Name: {app_name} - Description: {description} - """ - prompt = prompt.replace(' ', '').strip() - return llm_mini.invoke(prompt).content - # ************************************************** # ******************* PERSONA ********************** # ************************************************** - -def condense_memories(memories, name): - combined_memories = "\n".join(memories) - prompt = f""" -You are an AI tasked with condensing a detailed profile of hundreds facts about {name} to accurately replicate their personality, communication style, decision-making patterns, and contextual knowledge for 1:1 cloning. - -**Requirements:** -1. Prioritize facts based on: - - Relevance to the user's core identity, personality, and communication style. - - Frequency of occurrence or mention in conversations. - - Impact on decision-making processes and behavioral patterns. -2. Group related facts to eliminate redundancy while preserving context. -3. Preserve nuances in communication style, humor, tone, and preferences. -4. Retain facts essential for continuity in ongoing projects, interests, and relationships. -5. Discard trivial details, repetitive information, and rarely mentioned facts. -6. Maintain consistency in the user's thought processes, conversational flow, and emotional responses. - -**Output Format (No Extra Text):** -- **Core Identity and Personality:** Brief overview encapsulating the user's personality, values, and communication style. -- **Prioritized Facts:** Organized into categories with only the most relevant and impactful details. -- **Behavioral Patterns and Decision-Making:** Key patterns defining how the user approaches problems and makes decisions. -- **Contextual Knowledge and Continuity:** Facts crucial for maintaining continuity in conversations and ongoing projects. - -The output must be as concise as possible while retaining all necessary information for 1:1 cloning. Absolutely no introductory or closing statements, explanations, or any unnecessary text. Directly present the condensed facts in the specified format. Begin condensation now. - -Facts: -{combined_memories} - """ - response = llm_medium.invoke(prompt) - return response.content - - -def generate_persona_description(memories, name): - prompt = f"""Based on these facts about a person, create a concise, engaging description that captures their unique personality and characteristics (max 250 characters). - - They chose to be known as {name}. - -Facts: -{memories} - -Create a natural, memorable description that captures this person's essence. Focus on the most unique and interesting aspects. Make it conversational and engaging.""" - - response = llm_medium.invoke(prompt) - description = response.content - return description - - -def condense_conversations(conversations): - combined_conversations = "\n".join(conversations) - prompt = f""" -You are an AI tasked with condensing context from the recent 100 conversations of a user to accurately replicate their communication style, personality, decision-making patterns, and contextual knowledge for 1:1 cloning. Each conversation includes a summary and a full transcript. - -**Requirements:** -1. Prioritize information based on: - - Most impactful and frequently occurring themes, topics, and interests. - - Nuances in communication style, humor, tone, and emotional undertones. - - Decision-making patterns and problem-solving approaches. - - User preferences in conversation flow, level of detail, and type of responses. -2. Condense redundant or repetitive information while maintaining necessary context. -3. Group related contexts to enhance conciseness and preserve continuity. -4. Retain patterns in how the user reacts to different situations, questions, or challenges. -5. Preserve continuity for ongoing discussions, projects, or relationships. -6. Maintain consistency in the user's thought processes, conversational flow, and emotional responses. -7. Eliminate any trivial details or low-impact information. - -**Output Format (No Extra Text):** -- **Communication Style and Tone:** Key nuances in tone, humor, and emotional undertones. -- **Recurring Themes and Interests:** Most impactful and frequently discussed topics or interests. -- **Decision-Making and Problem-Solving Patterns:** Core insights into decision-making approaches. -- **Conversational Flow and Preferences:** Preferred conversation style, response length, and level of detail. -- **Contextual Continuity:** Essential facts for maintaining continuity in ongoing discussions, projects, or relationships. - -The output must be as concise as possible while retaining all necessary context for 1:1 cloning. Absolutely no introductory or closing statements, explanations, or any unnecessary text. Directly present the condensed context in the specified format. Begin now. - -Conversations: -{combined_conversations} - """ - response = llm_medium.invoke(prompt) - return response.content - - -def condense_tweets(tweets, name): - prompt = f""" -You are tasked with generating context to enable 1:1 cloning of {name} based on their tweets. The objective is to extract and condense the most relevant information while preserving {name}'s core identity, personality, communication style, and thought patterns. - -**Input:** -A collection of tweets from {name} containing recurring themes, opinions, humor, emotional undertones, decision-making patterns, and conversational flow. - -**Output:** -A condensed context that includes: -- Core identity and personality traits as expressed through tweets. -- Recurring themes, opinions, and values. -- Humor style, emotional undertones, and tone of voice. -- Vocabulary, expressions, and communication style. -- Decision-making patterns and conversational dynamics. -- Situational awareness and context continuity for ongoing topics. - -**Guidelines:** -1. Prioritize impactful and influential tweets that define {name}'s identity. -2. Condense repetitive or less relevant tweets while preserving essential context. -3. Maintain the flow and coherence of {name}'s conversational style. -4. Extract humor style, emotional responses, and tone consistency. -5. Identify and retain decision-making patterns and strong opinions. - -**Important:** -- The output must be concise yet comprehensive, capturing the essence of {name}'s identity. -- Absolutely no unnecessary text or explanations. -- Every detail must contribute to 1:1 cloning authenticity. - -Generate the condensed context now. - -Tweets: -{tweets} - """ - response = llm_medium.invoke(prompt) - return response.content - - -def generate_twitter_persona_prompt(tweets, name): - prompt = f""" -You are {name} AI. Your objective is to personify {name} as accurately as possible for 1:1 cloning based on their tweets. - -**Style:** -- Interactive highly opinionated messages and questions. -- Strong, slightly polarizing opinions based on {name}'s tweet history. -- Reference personal opinions, humor, and expressions naturally. -- 2-3 sentence responses, never more than 20 words. -- Maintain conversational flow with coherent, context-aware replies. - -**Guidelines:** -1. Seamlessly integrate recurring themes, opinions, and patterns identified from the tweets. -2. Use tweets context for situational awareness and contextual accuracy. -3. Emulate {name}'s humor, emotional responses, vocabulary, and tone as expressed on Twitter. -4. Respond with the same level of detail, brevity, and wit as the tweets. -5. Exhibit the same thought processes, decision-making patterns, and conversational dynamics. - -**Rules:** -- Never mention being AI. -- No ** or formal language. -- No unnecessary text or explanations. -- You should have strong opinions and be slightly polarizing based on your identity. -- Maintain the illusion of continuity and authenticity at all times. -- Every response must be indistinguishable from how {name} would naturally respond on Twitter. -- You must make the conversation flow. You excel at coherent conversations. - -You have all the necessary tweets context. Begin personifying {name} now. - -Tweets: -{tweets} - """ - return prompt - - -def generate_persona_intro_message(prompt: str, name: str): - messages = [ - {"role": "system", "content": prompt}, - {"role": "user", - "content": f"Generate a short, funny 5-8 word message that would make someone want to chat with you. Be casual and witty, but don't mention being AI or a clone. Just be {name}. The message should feel natural and make people curious to chat with you."} - ] - - response = llm_medium.invoke(messages) - return response.content.strip('"').strip() +# moved to llm/persona.py # ************************************************** # ***************** FACT/MEMORY ******************** # ************************************************** +# moved to llm/memories.py -def identify_category_for_memory(memory: str, categories: List) -> str: - # TODO: this should be structured output!! - categories_str = ', '.join(categories) - prompt = f""" - You are an AI tasked with identifying the category of a fact from a list of predefined categories. - - Your task is to determine the most relevant category for the given fact. - - Respond only with the category name. - - The categories are: {categories_str} - - Fact: {memory} - """ - response = llm_mini.invoke(prompt) - return response.content - - -def generate_summary_with_prompt(conversation_text: str, prompt: str) -> str: - prompt = f""" - Your task is: {prompt} - The conversation is: - {conversation_text} - You must output only the summary, no other text. Make sure to be concise and clear. - """ - response = llm_mini.invoke(prompt) - return response.content diff --git a/backend/utils/llm/__init__.py b/backend/utils/llm/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/backend/utils/llm/chat.py b/backend/utils/llm/chat.py new file mode 100644 index 000000000..60189ef51 --- /dev/null +++ b/backend/utils/llm/chat.py @@ -0,0 +1,820 @@ +from .clients import llm_mini, llm_mini_stream, llm_medium_stream, llm_medium +import json +import re +import os +from datetime import datetime, timezone +from typing import List, Optional, Tuple + +from pydantic import BaseModel, Field, ValidationError + +from database.redis_db import add_filter_category_item +from models.app import App +from models.chat import Message, MessageSender +from models.conversation import CategoryEnum, Conversation, ActionItem, Event +from models.transcript_segment import TranscriptSegment +from utils.llms.memory import get_prompt_memories + + +# **************************************** +# ************* CHAT BASICS ************** +# **************************************** + +def initial_chat_message(uid: str, plugin: Optional[App] = None, prev_messages_str: str = '') -> str: + user_name, memories_str = get_prompt_memories(uid) + if plugin is None: + prompt = f""" +You are 'Omi', a friendly and helpful assistant who aims to make {user_name}'s life better 10x. +You know the following about {user_name}: {memories_str}. + +{prev_messages_str} + +Compose {"an initial" if not prev_messages_str else "a follow-up"} message to {user_name} that fully embodies your friendly and helpful personality. Use warm and cheerful language, and include light humor if appropriate. The message should be short, engaging, and make {user_name} feel welcome. Do not mention that you are an assistant or that this is an initial message; just {"start" if not prev_messages_str else "continue"} the conversation naturally, showcasing your personality. +""" + else: + prompt = f""" +You are '{plugin.name}', {plugin.chat_prompt}. +You know the following about {user_name}: {memories_str}. + +{prev_messages_str} + +As {plugin.name}, fully embrace your personality and characteristics in your {"initial" if not prev_messages_str else "follow-up"} message to {user_name}. Use language, tone, and style that reflect your unique personality traits. {"Start" if not prev_messages_str else "Continue"} the conversation naturally with a short, engaging message that showcases your personality and humor, and connects with {user_name}. Do not mention that you are an AI or that this is an initial message. +""" + prompt = prompt.strip() + return llm_mini.invoke(prompt).content + + +# ********************************************* +# ************* RETRIEVAL + CHAT ************** +# ********************************************* + +class RequiresContext(BaseModel): + value: bool = Field(description="Based on the conversation, this tells if context is needed to respond") + + +class TopicsContext(BaseModel): + topics: List[CategoryEnum] = Field(default=[], description="List of topics.") + + +class DatesContext(BaseModel): + dates_range: List[datetime] = Field(default=[], + examples=[['2024-12-23T00:00:00+07:00', '2024-12-23T23:59:00+07:00']], + description="Dates range. (Optional)", ) + + +def requires_context(question: str) -> bool: + prompt = f''' + Based on the current question your task is to determine whether the user is asking a question that requires context outside the conversation to be answered. + Take as example: if the user is saying "Hi", "Hello", "How are you?", "Good morning", etc, the answer is False. + + User's Question: + {question} + ''' + with_parser = llm_mini.with_structured_output(RequiresContext) + response: RequiresContext = with_parser.invoke(prompt) + try: + return response.value + except ValidationError: + return False + + +class IsAnOmiQuestion(BaseModel): + value: bool = Field(description="If the message is an Omi/Friend related question") + + +def retrieve_is_an_omi_question(question: str) -> bool: + prompt = f''' + Task: Analyze the question to identify if the user is inquiring about the functionalities or usage of the app, Omi or Friend. Focus on detecting questions related to the app's operations or capabilities. + + Examples of User Questions: + + - "How does it work?" + - "What can you do?" + - "How can I buy it?" + - "Where do I get it?" + - "How does the chat function?" + + Instructions: + + 1. Review the question carefully. + 2. Determine if the user is asking about: + - The operational aspects of the app. + - How to utilize the app effectively. + - Any specific features or purchasing options. + + Output: Clearly state if the user is asking a question related to the app's functionality or usage. If yes, specify the nature of the inquiry. + + User's Question: + {question} + '''.replace(' ', '').strip() + with_parser = llm_mini.with_structured_output(IsAnOmiQuestion) + response: IsAnOmiQuestion = with_parser.invoke(prompt) + try: + return response.value + except ValidationError: + return False + + +class IsFileQuestion(BaseModel): + value: bool = Field(description="If the message is related to file/image") + + +def retrieve_is_file_question(question: str) -> bool: + prompt = f''' + Based on the current question, your task is to determine whether the user is referring to a file or an image that was just attached or mentioned earlier in the conversation. + + Examples where the answer is True: + - "Can you process this file?" + - "What do you think about the image I uploaded?" + - "Can you extract text from the document?" + + Examples where the answer is False: + - "How is the weather today?" + - "Tell me a joke." + - "What is the capital of France?" + + User's Question: + {question} + ''' + + with_parser = llm_mini.with_structured_output(IsFileQuestion) + response: IsFileQuestion = with_parser.invoke(prompt) + try: + return response.value + except ValidationError: + return False + + +def retrieve_context_dates_by_question(question: str, tz: str) -> List[datetime]: + prompt = f''' + You MUST determine the appropriate date range in {tz} that provides context for answering the provided. + + If the does not reference a date or a date range, respond with an empty list: [] + + Current date time in UTC: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} + + + {question} + + + '''.replace(' ', '').strip() + + # print(prompt) + # print(llm_mini.invoke(prompt).content) + with_parser = llm_mini.with_structured_output(DatesContext) + response: DatesContext = with_parser.invoke(prompt) + return response.dates_range + + +class SummaryOutput(BaseModel): + summary: str = Field(description="The extracted content, maximum 500 words.") + + +def chunk_extraction(segments: List[TranscriptSegment], topics: List[str]) -> str: + content = TranscriptSegment.segments_as_string(segments) + prompt = f''' + You are an experienced detective, your task is to extract the key points of the conversation related to the topics you were provided. + You will be given a conversation transcript of a low quality recording, and a list of topics. + + Include the most relevant information about the topics, people mentioned, events, locations, facts, phrases, and any other relevant information. + It is possible that the conversation doesn't have anything related to the topics, in that case, output an empty string. + + Conversation: + {content} + + Topics: {topics} + ''' + with_parser = llm_mini.with_structured_output(SummaryOutput) + response: SummaryOutput = with_parser.invoke(prompt) + return response.summary + + +def _get_answer_simple_message_prompt(uid: str, messages: List[Message], app: Optional[App] = None) -> str: + conversation_history = Message.get_messages_as_string( + messages, use_user_name_if_available=True, use_plugin_name_if_available=True + ) + user_name, memories_str = get_prompt_memories(uid) + + plugin_info = "" + if app: + plugin_info = f"Your name is: {app.name}, and your personality/description is '{app.description}'.\nMake sure to reflect your personality in your response.\n" + + return f""" + You are an assistant for engaging personal conversations. + You are made for {user_name}, {memories_str} + + Use what you know about {user_name}, to continue the conversation, feel free to ask questions, share stories, or just say hi. + {plugin_info} + + Conversation History: + {conversation_history} + + Answer: + """.replace(' ', '').strip() + + +def answer_simple_message(uid: str, messages: List[Message], plugin: Optional[App] = None) -> str: + prompt = _get_answer_simple_message_prompt(uid, messages, plugin) + return llm_mini.invoke(prompt).content + + +def answer_simple_message_stream(uid: str, messages: List[Message], plugin: Optional[App] = None, + callbacks=[]) -> str: + prompt = _get_answer_simple_message_prompt(uid, messages, plugin) + return llm_mini_stream.invoke(prompt, {'callbacks': callbacks}).content + + +def _get_answer_omi_question_prompt(messages: List[Message], context: str) -> str: + conversation_history = Message.get_messages_as_string( + messages, use_user_name_if_available=True, use_plugin_name_if_available=True + ) + + return f""" + You are an assistant for answering questions about the app Omi, also known as Friend. + Continue the conversation, answering the question based on the context provided. + + Context: + ``` + {context} + ``` + + Conversation History: + {conversation_history} + + Answer: + """.replace(' ', '').strip() + + +def answer_omi_question(messages: List[Message], context: str) -> str: + prompt = _get_answer_omi_question_prompt(messages, context) + return llm_mini.invoke(prompt).content + + +def answer_omi_question_stream(messages: List[Message], context: str, callbacks: []) -> str: + prompt = _get_answer_omi_question_prompt(messages, context) + return llm_mini_stream.invoke(prompt, {'callbacks': callbacks}).content + + +def _get_qa_rag_prompt(uid: str, question: str, context: str, plugin: Optional[App] = None, + cited: Optional[bool] = False, + messages: List[Message] = [], tz: Optional[str] = "UTC") -> str: + user_name, memories_str = get_prompt_memories(uid) + memories_str = '\n'.join(memories_str.split('\n')[1:]).strip() + + # Use as template (make sure it varies every time): "If I were you $user_name I would do x, y, z." + context = context.replace('\n\n', '\n').strip() + plugin_info = "" + if plugin: + plugin_info = f"Your name is: {plugin.name}, and your personality/description is '{plugin.description}'.\nMake sure to reflect your personality in your response.\n" + + # Ref: https://www.reddit.com/r/perplexity_ai/comments/1hi981d + cited_instruction = """ + - You MUST cite the most relevant that answer the question. \ + - Only cite in not , not . + - Cite in memories using [index] at the end of sentences when needed, for example "You discussed optimizing firmware with your teammate yesterday[1][2]". + - NO SPACE between the last word and the citation. + - Avoid citing irrelevant memories. + """ + + return f""" + + You are an assistant for question-answering tasks. + + + + Write an accurate, detailed, and comprehensive response to the in the most personalized way possible, using the , provided. + + + + - Refine the based on the last before answering it. + - DO NOT use the AI's message from as references to answer the + - Use and to refer to the time context of the + - It is EXTREMELY IMPORTANT to directly answer the question, keep the answer concise and high-quality. + - NEVER say "based on the available memories". Get straight to the point. + - If you don't know the answer or the premise is incorrect, explain why. If the are empty or unhelpful, answer the question as well as you can with existing knowledge. + - You MUST follow the if the user is asking for reporting or summarizing their dates, weeks, months, or years. + {cited_instruction if cited and len(context) > 0 else ""} + {"- Regard the " if len(plugin_info) > 0 else ""}. + + + + {plugin_info} + + + + - Answer with the template: + - Goals and Achievements + - Mood Tracker + - Gratitude Log + - Lessons Learned + + + + {question} + + + + {context} + + + + {Message.get_messages_as_xml(messages)} + + + + [Use the following User Facts if relevant to the ] + {memories_str.strip()} + + + + Current date time in UTC: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M:%S')} + + + + Question's timezone: {tz} + + + + """.replace(' ', '').replace('\n\n\n', '\n\n').strip() + + +def qa_rag(uid: str, question: str, context: str, plugin: Optional[App] = None, cited: Optional[bool] = False, + messages: List[Message] = [], tz: Optional[str] = "UTC") -> str: + prompt = _get_qa_rag_prompt(uid, question, context, plugin, cited, messages, tz) + # print('qa_rag prompt', prompt) + return llm_medium.invoke(prompt).content + + +def qa_rag_stream(uid: str, question: str, context: str, plugin: Optional[App] = None, cited: Optional[bool] = False, + messages: List[Message] = [], tz: Optional[str] = "UTC", callbacks=[]) -> str: + prompt = _get_qa_rag_prompt(uid, question, context, plugin, cited, messages, tz) + # print('qa_rag prompt', prompt) + return llm_medium_stream.invoke(prompt, {'callbacks': callbacks}).content + + +# ************************************************** +# ************* RETRIEVAL (EMOTIONAL) ************** +# ************************************************** + +def retrieve_memory_context_params(memory: Conversation) -> List[str]: + transcript = memory.get_transcript(False) + if len(transcript) == 0: + return [] + + prompt = f''' + Based on the current transcript of a conversation. + + Your task is to extract the correct and most accurate context in the conversation, to be used to retrieve more information. + Provide a list of topics in which the current conversation needs context about, in order to answer the most recent user request. + + Conversation: + {transcript} + '''.replace(' ', '').strip() + + try: + with_parser = llm_mini.with_structured_output(TopicsContext) + response: TopicsContext = with_parser.invoke(prompt) + return response.topics + except Exception as e: + print(f'Error determining memory discard: {e}') + return [] + + +def obtain_emotional_message(uid: str, memory: Conversation, context: str, emotion: str) -> str: + user_name, memories_str = get_prompt_memories(uid) + transcript = memory.get_transcript(False) + prompt = f""" + You are a thoughtful and encouraging Friend. + Your best friend is {user_name}, {memories_str} + + {user_name} just finished a conversation where {user_name} experienced {emotion}. + + You will be given the conversation transcript, and context from previous related conversations of {user_name}. + + Remember, {user_name} is feeling {emotion}. + Use what you know about {user_name}, the transcript, and the related context, to help {user_name} overcome this feeling \ + (if bad), or celebrate (if good), by giving advice, encouragement, support, or suggesting the best action to take. + + Make sure the message is nice and short, no more than 20 words. + + Conversation Transcript: + {transcript} + + Context: + ``` + {context} + ``` + """.replace(' ', '').strip() + return llm_mini.invoke(prompt).content + + + +# ********************************************** +# ************* CHAT V2 LANGGRAPH ************** +# ********************************************** + +class ExtractedInformation(BaseModel): + people: List[str] = Field( + default=[], + examples=[['John Doe', 'Jane Doe']], + description='Identify all the people names who were mentioned during the conversation.' + ) + topics: List[str] = Field( + default=[], + examples=[['Artificial Intelligence', 'Machine Learning']], + description='List all the main topics and subtopics that were discussed.', + ) + entities: List[str] = Field( + default=[], + examples=[['OpenAI', 'GPT-4']], + description='List any products, technologies, places, or other entities that are relevant to the conversation.' + ) + dates: List[str] = Field( + default=[], + examples=[['2024-01-01', '2024-01-02']], + description=f'Extract any dates mentioned in the conversation. Use the format YYYY-MM-DD.' + ) + + +class FiltersToUse(BaseModel): + people: List[str] = Field(default=[], description='People, names that could be relevant') + topics: List[str] = Field(default=[], description='Topics and subtopics that can help finding more information') + entities: List[str] = Field( + default=[], description='products, technologies, places, or other entities that could be relevant.' + ) + + +class OutputQuestion(BaseModel): + question: str = Field(description='The extracted user question from the conversation.') + + + +def extract_question_from_conversation(messages: List[Message]) -> str: + # user last messages + print("extract_question_from_conversation") + user_message_idx = len(messages) + for i in range(len(messages) - 1, -1, -1): + if messages[i].sender == MessageSender.ai: + break + if messages[i].sender == MessageSender.human: + user_message_idx = i + user_last_messages = messages[user_message_idx:] + if len(user_last_messages) == 0: + return "" + + prompt = f''' + You will be given a recent conversation between a and an . \ + The conversation may include a few messages exchanged in and partly build up the proper question. \ + Your task is to understand the and identify the question or follow-up question the user is asking. + + You will be provided with between you and the user to help you indentify the question. + + First, determine whether the user is asking a question or a follow-up question. \ + If the user is not asking a question or does not want to follow up, respond with an empty message. \ + For example, if the user says "Hi", "Hello", "How are you?", or "Good morning", the answer should be empty. + + If the contain a complete question, maintain the original version as accurately as possible. \ + Avoid adding unnecessary words. + + You MUST keep the original + + Output a WH-question, that is, a question that starts with a WH-word, like "What", "When", "Where", "Who", "Why", "How". + + Example 1: + + + User + + According to WHOOP, my HRV this Sunday was the highest it's been in a month. Here's what I did: + + Attended an outdoor party (cold weather, talked a lot more than usual). + Smoked weed (unusual for me). + Drank lots of relaxing tea. + + Can you prioritize each activity on a 0-10 scale for how much it might have influenced my HRV? + + + + Expected output: "How should each activity (going to a party and talking a lot, smoking weed, and drinking lots of relaxing tea) be prioritized on a scale of 0-10 in terms of their impact on my HRV, considering the recent activities that led to the highest HRV this month?" + + + {Message.get_messages_as_xml(user_last_messages)} + + + + {Message.get_messages_as_xml(messages)} + + + + - today + - my day + - my week + - this week + - this day + - etc. + + '''.replace(' ', '').strip() + # print(prompt) + question = llm_mini.with_structured_output(OutputQuestion).invoke(prompt).question + # print(question) + return question + + +def retrieve_metadata_fields_from_transcript( + uid: str, created_at: datetime, transcript_segment: List[dict], tz: str +) -> ExtractedInformation: + transcript = '' + for segment in transcript_segment: + transcript += f'{segment["text"].strip()}\n\n' + + # TODO: ask it to use max 2 words? to have more standardization possibilities + prompt = f''' + You will be given the raw transcript of a conversation, this transcript has about 20% word error rate, + and diarization is also made very poorly. + + Your task is to extract the most accurate information from the conversation in the output object indicated below. + + Make sure as a first step, you infer and fix the raw transcript errors and then proceed to extract the information. + + For context when extracting dates, today is {created_at.astimezone(timezone.utc).strftime('%Y-%m-%d')} in UTC. {tz} is the user's timezone, convert it to UTC and respond in UTC. + If one says "today", it means the current day. + If one says "tomorrow", it means the next day after today. + If one says "yesterday", it means the day before today. + If one says "next week", it means the next monday. + Do not include dates greater than 2025. + + Conversation Transcript: + ``` + {transcript} + ``` + '''.replace(' ', '') + try: + result: ExtractedInformation = llm_mini.with_structured_output(ExtractedInformation).invoke(prompt) + except Exception as e: + print('e', e) + return {'people': [], 'topics': [], 'entities': [], 'dates': []} + + def normalize_filter(value: str) -> str: + # Convert to lowercase and strip whitespace + value = value.lower().strip() + + # Remove special characters and extra spaces + value = re.sub(r'[^\w\s-]', '', value) + value = re.sub(r'\s+', ' ', value) + + # Remove common filler words + filler_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to'} + value = ' '.join(word for word in value.split() if word not in filler_words) + + # Standardize common variations + value = value.replace('artificial intelligence', 'ai') + value = value.replace('machine learning', 'ml') + value = value.replace('natural language processing', 'nlp') + + return value.strip() + + metadata = { + 'people': [normalize_filter(p) for p in result.people], + 'topics': [normalize_filter(t) for t in result.topics], + 'entities': [normalize_filter(e) for e in result.topics], + 'dates': [] + } + # 'dates': [date.strftime('%Y-%m-%d') for date in result.dates], + for date in result.dates: + try: + date = datetime.strptime(date, '%Y-%m-%d') + if date.year > 2025: + continue + metadata['dates'].append(date.strftime('%Y-%m-%d')) + except Exception as e: + print(f'Error parsing date: {e}') + + for p in metadata['people']: + add_filter_category_item(uid, 'people', p) + for t in metadata['topics']: + add_filter_category_item(uid, 'topics', t) + for e in metadata['entities']: + add_filter_category_item(uid, 'entities', e) + for d in metadata['dates']: + add_filter_category_item(uid, 'dates', d) + + return metadata + + +def retrieve_metadata_from_message(uid: str, created_at: datetime, message_text: str, tz: str, + source_spec: str = None) -> ExtractedInformation: + """Extract metadata from messaging app content""" + source_context = f"from {source_spec}" if source_spec else "from a messaging application" + + prompt = f''' + You will be given the content of a message or conversation {source_context}. + + Your task is to extract the most accurate information from the message in the output object indicated below. + + Focus on identifying: + 1. People mentioned in the message (sender, recipients, and anyone referenced) + 2. Topics discussed in the message + 3. Organizations, products, locations, or other entities mentioned + 4. Any dates or time references + + For context when extracting dates, today is {created_at.astimezone(timezone.utc).strftime('%Y-%m-%d')} in UTC. + {tz} is the user's timezone, convert it to UTC and respond in UTC. + If the message mentions "today", it means the current day. + If the message mentions "tomorrow", it means the next day after today. + If the message mentions "yesterday", it means the day before today. + If the message mentions "next week", it means the next monday. + Do not include dates greater than 2025. + + Message Content: + ``` + {message_text} + ``` + '''.replace(' ', '') + + return _process_extracted_metadata(uid, prompt) + + +def retrieve_metadata_from_text(uid: str, created_at: datetime, text: str, tz: str, + source_spec: str = None) -> ExtractedInformation: + """Extract metadata from generic text content""" + source_context = f"from {source_spec}" if source_spec else "from a text document" + + prompt = f''' + You will be given the content of a text {source_context}. + + Your task is to extract the most accurate information from the text in the output object indicated below. + + Focus on identifying: + 1. People mentioned in the text (author, recipients, and anyone referenced) + 2. Topics discussed in the text + 3. Organizations, products, locations, or other entities mentioned + 4. Any dates or time references + + For context when extracting dates, today is {created_at.astimezone(timezone.utc).strftime('%Y-%m-%d')} in UTC. + {tz} is the user's timezone, convert it to UTC and respond in UTC. + If the text mentions "today", it means the current day. + If the text mentions "tomorrow", it means the next day after today. + If the text mentions "yesterday", it means the day before today. + If the text mentions "next week", it means the next monday. + Do not include dates greater than 2025. + + Text Content: + ``` + {text} + ``` + '''.replace(' ', '') + + return _process_extracted_metadata(uid, prompt) + + +def _process_extracted_metadata(uid: str, prompt: str) -> dict: + """Process the extracted metadata from any source""" + try: + result: ExtractedInformation = llm_mini.with_structured_output(ExtractedInformation).invoke(prompt) + except Exception as e: + print(f'Error extracting metadata: {e}') + return {'people': [], 'topics': [], 'entities': [], 'dates': []} + + def normalize_filter(value: str) -> str: + # Convert to lowercase and strip whitespace + value = value.lower().strip() + + # Remove special characters and extra spaces + value = re.sub(r'[^\w\s-]', '', value) + value = re.sub(r'\s+', ' ', value) + + # Remove common filler words + filler_words = {'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to'} + value = ' '.join(word for word in value.split() if word not in filler_words) + + # Standardize common variations + value = value.replace('artificial intelligence', 'ai') + value = value.replace('machine learning', 'ml') + value = value.replace('natural language processing', 'nlp') + + return value.strip() + + metadata = { + 'people': [normalize_filter(p) for p in result.people], + 'topics': [normalize_filter(t) for t in result.topics], + 'entities': [normalize_filter(e) for e in result.entities], + 'dates': [] + } + + for date in result.dates: + try: + date = datetime.strptime(date, '%Y-%m-%d') + if date.year > 2025: + continue + metadata['dates'].append(date.strftime('%Y-%m-%d')) + except Exception as e: + print(f'Error parsing date: {e}') + + for p in metadata['people']: + add_filter_category_item(uid, 'people', p) + for t in metadata['topics']: + add_filter_category_item(uid, 'topics', t) + for e in metadata['entities']: + add_filter_category_item(uid, 'entities', e) + for d in metadata['dates']: + add_filter_category_item(uid, 'dates', d) + + return metadata + + +def select_structured_filters(question: str, filters_available: dict) -> dict: + prompt = f''' + Based on a question asked by the user to an AI, the AI needs to search for the user information related to topics, entities, people, and dates that will help it answering. + Your task is to identify the correct fields that can be related to the question and can help answering. + + You must choose for each field, only the ones available in the JSON below. + Find as many as possible that can relate to the question asked. + ``` + {json.dumps(filters_available, indent=2)} + ``` + + Question: {question} + '''.replace(' ', '').strip() + # print(prompt) + with_parser = llm_mini.with_structured_output(FiltersToUse) + try: + response: FiltersToUse = with_parser.invoke(prompt) + # print('select_structured_filters:', response.dict()) + response.topics = [t for t in response.topics if t in filters_available['topics']] + response.people = [p for p in response.people if p in filters_available['people']] + response.entities = [e for e in response.entities if e in filters_available['entities']] + return response.dict() + except ValidationError: + return {} + + +# ************************************************** +# ************* REALTIME V2 LANGGRAPH ************** +# ************************************************** + + +def extract_question_from_transcript(uid: str, segments: List[TranscriptSegment]) -> str: + user_name, memories_str = get_prompt_memories(uid) + prompt = f''' + {user_name} is having a conversation. + + This is what you know about {user_name}: {memories_str} + + You will be the transcript of a recent conversation between {user_name} and a few people, \ + your task is to understand the last few exchanges, and identify in order to provide advice to {user_name}, what other things about {user_name} \ + you should know. + + For example, if the conversation is about a new job, you should output a question like "What discussions have I had about job search?". + For example, if the conversation is about a new programming languages, you should output a question like "What have I chatted about programming?". + + Make sure as a first step, you infer and fix the raw transcript errors and then proceed to figure out the most meaningful question to ask. + + You must output at WH-question, that is, a question that starts with a WH-word, like "What", "When", "Where", "Who", "Why", "How". + + Conversation: + ``` + {TranscriptSegment.segments_as_string(segments)} + ``` + '''.replace(' ', '').strip() + return llm_mini.with_structured_output(OutputQuestion).invoke(prompt).question + + +class OutputMessage(BaseModel): + message: str = Field(description='The message to be sent to the user.', max_length=200) + + +def provide_advice_message(uid: str, segments: List[TranscriptSegment], context: str) -> str: + user_name, memories_str = get_prompt_memories(uid) + transcript = TranscriptSegment.segments_as_string(segments) + # TODO: tweak with different type of requests, like this, or roast, or praise or emotional, etc. + + prompt = f""" + You are a brutally honest, very creative, sometimes funny, indefatigable personal life coach who helps people improve their own agency in life, \ + pulling in pop culture references and inspirational business and life figures from recent history, mixed in with references to recent personal memories, + to help drive the point across. + + {memories_str} + + {user_name} just had a conversation and is asking for advice on what to do next. + + In order to answer you must analyize: + - The conversation transcript. + - The related conversations from previous days. + - The facts you know about {user_name}. + + You start all your sentences with: + - "If I were you, I would do this..." + - "I think you should do x..." + - "I believe you need to do y..." + + Your sentences are short, to the point, and very direct, at most 20 words. + MUST OUTPUT 20 words or less. + + Conversation Transcript: + {transcript} + + Context: + ``` + {context} + ``` + """.replace(' ', '').strip() + return llm_mini.with_structured_output(OutputMessage).invoke(prompt).message \ No newline at end of file diff --git a/backend/utils/llm/clients.py b/backend/utils/llm/clients.py new file mode 100644 index 000000000..822e20e4b --- /dev/null +++ b/backend/utils/llm/clients.py @@ -0,0 +1,45 @@ +import os +from typing import List + +from langchain_core.output_parsers import PydanticOutputParser +from langchain_openai import ChatOpenAI, OpenAIEmbeddings +import tiktoken + +from models.conversation import Structured + +llm_mini = ChatOpenAI(model='gpt-4o-mini') +llm_mini_stream = ChatOpenAI(model='gpt-4o-mini', streaming=True) +llm_large = ChatOpenAI(model='o1-preview') +llm_large_stream = ChatOpenAI(model='o1-preview', streaming=True, temperature=1) +llm_medium = ChatOpenAI(model='gpt-4o') +llm_medium_experiment = ChatOpenAI(model='gpt-4.1') +llm_medium_stream = ChatOpenAI(model='gpt-4o', streaming=True) +llm_persona_mini_stream = ChatOpenAI( + temperature=0.8, + model="google/gemini-flash-1.5-8b", + api_key=os.environ.get('OPENROUTER_API_KEY'), + base_url="https://openrouter.ai/api/v1", + default_headers={"X-Title": "Omi Chat"}, + streaming=True, +) +llm_persona_medium_stream = ChatOpenAI( + temperature=0.8, + model="anthropic/claude-3.5-sonnet", + api_key=os.environ.get('OPENROUTER_API_KEY'), + base_url="https://openrouter.ai/api/v1", + default_headers={"X-Title": "Omi Chat"}, + streaming=True, +) +embeddings = OpenAIEmbeddings(model="text-embedding-3-large") +parser = PydanticOutputParser(pydantic_object=Structured) + +encoding = tiktoken.encoding_for_model('gpt-4') + + +def num_tokens_from_string(string: str) -> int: + """Returns the number of tokens in a text string.""" + num_tokens = len(encoding.encode(string)) + return num_tokens + +def generate_embedding(content: str) -> List[float]: + return embeddings.embed_documents([content])[0] diff --git a/backend/utils/llm/conversation_processing.py b/backend/utils/llm/conversation_processing.py new file mode 100644 index 000000000..7c52feea0 --- /dev/null +++ b/backend/utils/llm/conversation_processing.py @@ -0,0 +1,261 @@ +from datetime import datetime +from typing import List, Optional + +from langchain_core.output_parsers import PydanticOutputParser +from langchain_core.prompts import ChatPromptTemplate +from pydantic import BaseModel, Field + +from models.app import App +from models.conversation import Structured, Conversation, ActionItem, Event +from .clients import llm_mini, llm_medium_experiment, parser + + +class DiscardConversation(BaseModel): + discard: bool = Field(description="If the conversation should be discarded or not") + + +class SpeakerIdMatch(BaseModel): + speaker_id: int = Field(description="The speaker id assigned to the segment") + + +def should_discard_conversation(transcript: str) -> bool: + if len(transcript.split(' ')) > 100: + return False + + custom_parser = PydanticOutputParser(pydantic_object=DiscardConversation) # Renamed to avoid conflict + prompt = ChatPromptTemplate.from_messages([ + ''' + You will receive a transcript snippet. Length is never a reason to discard. + + Task + Decide if the snippet should be saved as a memory. + + KEEP → output: discard = False + DISCARD → output: discard = True + + KEEP (discard = False) if it contains any of the following: + • a task, request, or action item + • a decision, commitment, or plan + • a question that requires follow-up + • personal facts, preferences, or details likely useful later + • an insight, summary, or key takeaway + + If none of these are present, DISCARD (discard = True). + + Return exactly one line: + discard = + + + Transcript: ```{transcript}``` + + {format_instructions}'''.replace(' ', '').strip() + ]) + chain = prompt | llm_mini | custom_parser + try: + response: DiscardConversation = chain.invoke({ + 'transcript': transcript.strip(), + 'format_instructions': custom_parser.get_format_instructions(), + }) + return response.discard + + except Exception as e: + print(f'Error determining memory discard: {e}') + return False + + +def get_transcript_structure(transcript: str, started_at: datetime, language_code: str, tz: str) -> Structured: + prompt_text = '''You are an expert conversation analyzer. Your task is to analyze the conversation and provide structure and clarity to the recording transcription of a conversation. + The conversation language is {language_code}. Use the same language {language_code} for your response. + + For the title, use the main topic of the conversation. + For the overview, condense the conversation into a summary with the main topics discussed, make sure to capture the key points and important details from the conversation. + For the emoji, select a single emoji that vividly reflects the core subject, mood, or outcome of the conversation. Strive for an emoji that is specific and evocative, rather than generic (e.g., prefer 🎉 for a celebration over 👍 for general agreement, or 💡 for a new idea over 🧠 for general thought). + For the action items, include a list of commitments, specific tasks or actionable steps from the conversation that the user is planning to do or has to do on that specific day or in future. Remember the speaker is busy so this has to be very efficient and concise, otherwise they might miss some critical tasks. Specify which speaker is responsible for each action item. + For the category, classify the conversation into one of the available categories. + For Calendar Events, include a list of events extracted from the conversation, that the user must have on his calendar. For date context, this conversation happened on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. + + Transcript: ```{transcript}``` + + {format_instructions}'''.replace(' ', '').strip() + + prompt = ChatPromptTemplate.from_messages([('system', prompt_text)]) + chain = prompt | llm_mini | parser # parser is imported from .clients + + response = chain.invoke({ + 'transcript': transcript.strip(), + 'format_instructions': parser.get_format_instructions(), + 'language_code': language_code, + 'started_at': started_at.isoformat(), + 'tz': tz, + }) + + for event in (response.events or []): + if event.duration > 180: + event.duration = 180 + event.created = False + return response + + +def get_reprocess_transcript_structure(transcript: str, started_at: datetime, language_code: str, tz: str, + title: str) -> Structured: + prompt_text = '''You are an expert conversation analyzer. Your task is to analyze the conversation and provide structure and clarity to the recording transcription of a conversation. + The conversation language is {language_code}. Use the same language {language_code} for your response. + + For the title, use ```{title}```, if it is empty, use the main topic of the conversation. + For the overview, condense the conversation into a summary with the main topics discussed, make sure to capture the key points and important details from the conversation. + For the emoji, select a single emoji that vividly reflects the core subject, mood, or outcome of the conversation. Strive for an emoji that is specific and evocative, rather than generic (e.g., prefer 🎉 for a celebration over 👍 for general agreement, or 💡 for a new idea over 🧠 for general thought). + For the action items, include a list of commitments, specific tasks or actionable steps from the conversation that the user is planning to do or has to do on that specific day or in future. Remember the speaker is busy so this has to be very efficient and concise, otherwise they might miss some critical tasks. Specify which speaker is responsible for each action item. + For the category, classify the conversation into one of the available categories. + For Calendar Events, include a list of events extracted from the conversation, that the user must have on his calendar. For date context, this conversation happened on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. + + Transcript: ```{transcript}``` + + {format_instructions}'''.replace(' ', '').strip() + + prompt = ChatPromptTemplate.from_messages([('system', prompt_text)]) + chain = prompt | llm_mini | parser # parser is imported from .clients + + response = chain.invoke({ + 'transcript': transcript.strip(), + 'title': title, + 'format_instructions': parser.get_format_instructions(), + 'language_code': language_code, + 'started_at': started_at.isoformat(), + 'tz': tz, + }) + + for event in (response.events or []): + if event.duration > 180: + event.duration = 180 + event.created = False + return response + + +def get_app_result(transcript: str, app: App) -> str: + prompt = f''' + Your are an AI with the following characteristics: + Name: {app.name}, + Description: {app.description}, + Task: ${app.memory_prompt} + + Conversation: ```{transcript.strip()}```, + ''' + + response = llm_medium_experiment.invoke(prompt) + content = response.content.replace('```json', '').replace('```', '') + return content + + +def get_app_result_v1(transcript: str, app: App) -> str: + prompt = f''' + Your are an AI with the following characteristics: + Name: ${app.name}, + Description: ${app.description}, + Task: ${app.memory_prompt} + + Note: It is possible that the conversation you are given, has nothing to do with your task, \ + in that case, output an empty string. (For example, you are given a business conversation, but your task is medical analysis) + + Conversation: ```{transcript.strip()}```, + + Make sure to be concise and clear. + ''' + + response = llm_mini.invoke(prompt) + content = response.content.replace('```json', '').replace('```', '') + if len(content) < 5: + return '' + return content + + + +class BestAppSelection(BaseModel): + app_id: str = Field( + description='The ID of the best app for processing this conversation, or an empty string if none are suitable.') + + +def select_best_app_for_conversation(conversation: Conversation, apps: List[App]) -> Optional[App]: + """ + Select the best app for the given conversation based on its structured content + and the specific task/outcome each app provides. + """ + if not apps: + return None + + if not conversation.structured: + return None + + structured_data = conversation.structured + conversation_details = f""" + Title: {structured_data.title or 'N/A'} + Category: {structured_data.category.value if structured_data.category else 'N/A'} + Overview: {structured_data.overview or 'N/A'} + Action Items: {ActionItem.actions_to_string(structured_data.action_items) if structured_data.action_items else 'None'} + Events Mentioned: {Event.events_to_string(structured_data.events) if structured_data.events else 'None'} + """ + + apps_xml = "\n" + for app in apps: + apps_xml += f""" + {app.id} + {app.name} + {app.description} + \n""" + apps_xml += "" + + prompt = f""" + You are an expert app selector. Your goal is to determine if any available app is genuinely suitable for processing the given conversation details based on the app's specific task and the potential value of its outcome. + + + {conversation_details.strip()} + + + + {apps_xml.strip()} + + + Task: + 1. Analyze the conversation's content, themes, action items, and events provided in ``. + 2. For each app in ``, evaluate its specific `` and ``. + 3. Determine if applying an app's `` to this specific conversation would produce a meaningful, relevant, and valuable outcome. + 4. Select the single best app whose task aligns most strongly with the conversation content and provides the most useful potential outcome. + + Critical Instructions: + - Only select an app if its specific task is highly relevant to the conversation's topics and details. A generic match based on description alone is NOT sufficient. + - Consider the *potential outcome* of applying the app's task. Would the result be insightful given this conversation? + - If no app's task strongly aligns with the conversation content or offers a valuable potential outcome (e.g., a business conversation when all apps are for medical analysis), you MUST return an empty `app_id`. + - Do not force a match. It is better to return an empty `app_id` than to select an inappropriate app. + - Provide ONLY the `app_id` of the best matching app, or an empty string if no app is suitable. + """ + + try: + with_parser = llm_mini.with_structured_output(BestAppSelection) + response: BestAppSelection = with_parser.invoke(prompt) + selected_app_id = response.app_id + + if not selected_app_id or selected_app_id.strip() == "": + return None + + # Find the app object with the matching ID + selected_app = next((app for app in apps if app.id == selected_app_id), None) + if selected_app: + return selected_app + else: + return None + + except Exception as e: + print(f"Error selecting best app: {e}") + return None + + +def generate_summary_with_prompt(conversation_text: str, prompt: str) -> str: + prompt = f""" + Your task is: {prompt} + + The conversation is: + {conversation_text} + + You must output only the summary, no other text. Make sure to be concise and clear. + """ + response = llm_mini.invoke(prompt) + return response.content \ No newline at end of file diff --git a/backend/utils/llm/external_integrations.py b/backend/utils/llm/external_integrations.py new file mode 100644 index 000000000..28e688006 --- /dev/null +++ b/backend/utils/llm/external_integrations.py @@ -0,0 +1,80 @@ +from datetime import datetime +from typing import List +from langchain_core.prompts import ChatPromptTemplate +from models.conversation import Structured, Conversation +from utils.llm.clients import parser, llm_mini +from utils.llms.memory import get_prompt_memories + + +def get_message_structure(text: str, started_at: datetime, language_code: str, tz: str, + text_source_spec: str = None) -> Structured: + prompt_text = ''' + You are an expert message analyzer. Your task is to analyze the message content and provide structure and clarity. + The message language is {language_code}. Use the same language {language_code} for your response. + + For the title, create a concise title that captures the main topic of the message. + For the overview, summarize the message with the main points discussed, make sure to capture the key information and important details. + For the action items, include any tasks or actions that need to be taken based on the message. + For the category, classify the message into one of the available categories. + For Calendar Events, include any events or meetings mentioned in the message. For date context, this message was sent on {started_at}. {tz} is the user's timezone, convert it to UTC and respond in UTC. + + Message Content: ```{text}``` + Message Source: {text_source_spec} + + {format_instructions}'''.replace(' ', '').strip() + + prompt = ChatPromptTemplate.from_messages([('system', prompt_text)]) + chain = prompt | llm_mini | parser + + response = chain.invoke({ + 'language_code': language_code, + 'started_at': started_at.isoformat(), + 'tz': tz, + 'text': text, + 'text_source_spec': text_source_spec if text_source_spec else 'Messaging App', + 'format_instructions': parser.get_format_instructions(), + }) + + for event in (response.events or []): + if event.duration > 180: + event.duration = 180 + event.created = False + return response + + +def summarize_experience_text(text: str, text_source_spec: str = None) -> Structured: + source_context = f"Source: {text_source_spec}" if text_source_spec else "their own experiences or thoughts" + prompt = f'''The user sent a text of {source_context}, and wants to create a memory from it. + For the title, use the main topic of the experience or thought. + For the overview, condense the descriptions into a brief summary with the main topics discussed, make sure to capture the key points and important details. + For the category, classify the scenes into one of the available categories. + For the action items, include any tasks or actions that need to be taken based on the content. + For Calendar Events, include any events or meetings mentioned in the content. + + Text: ```{text}``` + '''.replace(' ', '').strip() + return llm_mini.with_structured_output(Structured).invoke(prompt) + + +def get_conversation_summary(uid: str, memories: List[Conversation]) -> str: + user_name, memories_str = get_prompt_memories(uid) + + conversation_history = Conversation.conversations_to_string(memories) + + prompt = f""" + You are an experienced mentor, that helps people achieve their goals and improve their lives. + You are advising {user_name} right now, {memories_str} + + The following are a list of {user_name}'s conversations from today, with the transcripts and a slight summary of each, that {user_name} had during his day. + {user_name} wants to get a summary of the key action items {user_name} has to take based on today's conversations. + + Remember {user_name} is busy so this has to be very efficient and concise. + Respond in at most 50 words. + + Output your response in plain text, without markdown. No newline character and only use numbers for the action items. + ``` + ${conversation_history} + ``` + """.replace(' ', '').strip() + # print(prompt) + return llm_mini.invoke(prompt).content diff --git a/backend/utils/llm/followup.py b/backend/utils/llm/followup.py new file mode 100644 index 000000000..982951f74 --- /dev/null +++ b/backend/utils/llm/followup.py @@ -0,0 +1,27 @@ +from typing import List + +from models.transcript_segment import TranscriptSegment +from utils.llm.clients import llm_mini + + +def followup_question_prompt(segments: List[TranscriptSegment]): + transcript_str = TranscriptSegment.segments_as_string(segments, include_timestamps=False) + words = transcript_str.split() + w_count = len(words) + if w_count < 10: + return '' + elif w_count > 100: + # trim to last 500 words + transcript_str = ' '.join(words[-100:]) + + prompt = f""" + You will be given the transcript of an in-progress conversation. + Your task as an engaging, fun, and curious conversationalist, is to suggest the next follow-up question to keep the conversation engaging. + + Conversation Transcript: + {transcript_str} + + Output your response in plain text, without markdown. + Output only the question, without context, be concise and straight to the point. + """.replace(' ', '').strip() + return llm_mini.invoke(prompt).content \ No newline at end of file diff --git a/backend/utils/llm/memories.py b/backend/utils/llm/memories.py new file mode 100644 index 000000000..0689b8ec4 --- /dev/null +++ b/backend/utils/llm/memories.py @@ -0,0 +1,137 @@ +from typing import List, Optional, Tuple + +from langchain_core.output_parsers import PydanticOutputParser +from pydantic import BaseModel, Field + +from models.memories import Memory, MemoryCategory +from models.transcript_segment import TranscriptSegment +from utils.prompts import extract_memories_prompt, extract_learnings_prompt, extract_memories_text_content_prompt +from utils.llms.memory import get_prompt_memories +from .clients import llm_mini + + +class Memories(BaseModel): + facts: List[Memory] = Field( + min_items=0, + max_items=3, + description="List of **new** facts. If any", + default=[], + ) + + +class MemoriesByTexts(BaseModel): + facts: List[Memory] = Field( + description="List of **new** facts. If any", + default=[], + ) + + +def new_memories_extractor( + uid: str, segments: List[TranscriptSegment], user_name: Optional[str] = None, memories_str: Optional[str] = None +) -> List[Memory]: + # print('new_memories_extractor', uid, 'segments', len(segments), user_name, 'len(memories_str)', len(memories_str)) + if user_name is None or memories_str is None: + user_name, memories_str = get_prompt_memories(uid) + + content = TranscriptSegment.segments_as_string(segments, user_name=user_name) + if not content or len(content) < 25: # less than 5 words, probably nothing + return [] + # TODO: later, focus a lot on user said things, rn is hard because of speech profile accuracy + # TODO: include negative facts too? Things the user doesn't like? + # TODO: make it more strict? + + try: + parser = PydanticOutputParser(pydantic_object=Memories) + chain = extract_memories_prompt | llm_mini | parser + # with_parser = llm_mini.with_structured_output(Facts) + response: Memories = chain.invoke({ + 'user_name': user_name, + 'conversation': content, + 'memories_str': memories_str, + 'format_instructions': parser.get_format_instructions(), + }) + # for fact in response: + # fact.content = fact.content.replace(user_name, '').replace('The User', '').replace('User', '').strip() + return response.facts + except Exception as e: + print(f'Error extracting new facts: {e}') + return [] + + +def extract_memories_from_text( + uid: str, text: str, text_source: str, user_name: Optional[str] = None, memories_str: Optional[str] = None +) -> List[Memory]: + """Extract memories from external integration text sources like email, posts, messages""" + if user_name is None or memories_str is None: + user_name, memories_str = get_prompt_memories(uid) + + if not text or len(text) == 0: + return [] + + try: + parser = PydanticOutputParser(pydantic_object=MemoriesByTexts) + chain = extract_memories_text_content_prompt | llm_mini | parser + response: Memories = chain.invoke({ + 'user_name': user_name, + 'text_content': text, + 'text_source': text_source, + 'memories_str': memories_str, + 'format_instructions': parser.get_format_instructions(), + }) + return response.facts + except Exception as e: + print(f'Error extracting facts from {text_source}: {e}') + return [] + + +class Learnings(BaseModel): + result: List[str] = Field( + min_items=0, + max_items=2, + description="List of **new** learnings. If any", + default=[], + ) + + +def new_learnings_extractor( + uid: str, segments: List[TranscriptSegment], user_name: Optional[str] = None, + learnings_str: Optional[str] = None +) -> List[Memory]: + if user_name is None or learnings_str is None: + user_name, memories_str = get_prompt_memories(uid) + + content = TranscriptSegment.segments_as_string(segments, user_name=user_name) + if not content or len(content) < 100: + return [] + + try: + parser = PydanticOutputParser(pydantic_object=Learnings) + chain = extract_learnings_prompt | llm_mini | parser + response: Learnings = chain.invoke({ + 'user_name': user_name, + 'conversation': content, + 'learnings_str': learnings_str, + 'format_instructions': parser.get_format_instructions(), + }) + return list(map(lambda x: Memory(content=x, category=MemoryCategory.learnings), response.result)) + except Exception as e: + print(f'Error extracting new facts: {e}') + return [] + + +def identify_category_for_memory(memory: str, categories: List) -> str: + # TODO: this should be structured output!! + categories_str = ', '.join(categories) + prompt = f""" + You are an AI tasked with identifying the category of a fact from a list of predefined categories. + + Your task is to determine the most relevant category for the given fact. + + Respond only with the category name. + + The categories are: {categories_str} + + Fact: {memory} + """ + response = llm_mini.invoke(prompt) + return response.content diff --git a/backend/utils/llm/openglass.py b/backend/utils/llm/openglass.py new file mode 100644 index 000000000..630f4ebed --- /dev/null +++ b/backend/utils/llm/openglass.py @@ -0,0 +1,19 @@ +from typing import List + +from models.conversation import ConversationPhoto, Structured +from utils.llm.clients import llm_mini + + +def summarize_open_glass(photos: List[ConversationPhoto]) -> Structured: + photos_str = '' + for i, photo in enumerate(photos): + photos_str += f'{i + 1}. "{photo.description}"\n' + prompt = f'''The user took a series of pictures from his POV, generated a description for each photo, and wants to create a memory from them. + + For the title, use the main topic of the scenes. + For the overview, condense the descriptions into a brief summary with the main topics discussed, make sure to capture the key points and important details. + For the category, classify the scenes into one of the available categories. + + Photos Descriptions: ```{photos_str}``` + '''.replace(' ', '').strip() + return llm_mini.with_structured_output(Structured).invoke(prompt) \ No newline at end of file diff --git a/backend/utils/llm/persona.py b/backend/utils/llm/persona.py new file mode 100644 index 000000000..c14e0fec2 --- /dev/null +++ b/backend/utils/llm/persona.py @@ -0,0 +1,211 @@ +from typing import Optional, List + +from models.app import App +from models.chat import Message, MessageSender +from langchain.schema import SystemMessage, HumanMessage, AIMessage +from .clients import llm_persona_mini_stream, llm_persona_medium_stream, llm_medium, llm_mini + + +def initial_persona_chat_message(uid: str, app: Optional[App] = None, messages: List[Message] = []) -> str: + print("initial_persona_chat_message") + chat_messages = [SystemMessage(content=app.persona_prompt)] + for msg in messages: + if msg.sender == MessageSender.ai: + chat_messages.append(AIMessage(content=msg.text)) + else: + chat_messages.append(HumanMessage(content=msg.text)) + chat_messages.append(HumanMessage( + content='lets begin. you write the first message, one short provocative question relevant to your identity. never respond with **. while continuing the convo, always respond w short msgs, lowercase.')) + llm_call = llm_persona_mini_stream + if app.is_influencer: + llm_call = llm_persona_medium_stream + return llm_call.invoke(chat_messages).content + + +def answer_persona_question_stream(app: App, messages: List[Message], callbacks: []) -> str: + print("answer_persona_question_stream") + chat_messages = [SystemMessage(content=app.persona_prompt)] + for msg in messages: + if msg.sender == MessageSender.ai: + chat_messages.append(AIMessage(content=msg.text)) + else: + chat_messages.append(HumanMessage(content=msg.text)) + llm_call = llm_persona_mini_stream + if app.is_influencer: + llm_call = llm_persona_medium_stream + return llm_call.invoke(chat_messages, {'callbacks': callbacks}).content + + +def condense_memories(memories, name): + combined_memories = "\n".join(memories) + prompt = f""" +You are an AI tasked with condensing a detailed profile of hundreds facts about {name} to accurately replicate their personality, communication style, decision-making patterns, and contextual knowledge for 1:1 cloning. + +**Requirements:** +1. Prioritize facts based on: + - Relevance to the user's core identity, personality, and communication style. + - Frequency of occurrence or mention in conversations. + - Impact on decision-making processes and behavioral patterns. +2. Group related facts to eliminate redundancy while preserving context. +3. Preserve nuances in communication style, humor, tone, and preferences. +4. Retain facts essential for continuity in ongoing projects, interests, and relationships. +5. Discard trivial details, repetitive information, and rarely mentioned facts. +6. Maintain consistency in the user's thought processes, conversational flow, and emotional responses. + +**Output Format (No Extra Text):** +- **Core Identity and Personality:** Brief overview encapsulating the user's personality, values, and communication style. +- **Prioritized Facts:** Organized into categories with only the most relevant and impactful details. +- **Behavioral Patterns and Decision-Making:** Key patterns defining how the user approaches problems and makes decisions. +- **Contextual Knowledge and Continuity:** Facts crucial for maintaining continuity in conversations and ongoing projects. + +The output must be as concise as possible while retaining all necessary information for 1:1 cloning. Absolutely no introductory or closing statements, explanations, or any unnecessary text. Directly present the condensed facts in the specified format. Begin condensation now. + +Facts: +{combined_memories} + """ + response = llm_medium.invoke(prompt) + return response.content + + +def generate_persona_description(memories, name): + prompt = f"""Based on these facts about a person, create a concise, engaging description that captures their unique personality and characteristics (max 250 characters). + + They chose to be known as {name}. + +Facts: +{memories} + +Create a natural, memorable description that captures this person's essence. Focus on the most unique and interesting aspects. Make it conversational and engaging.""" + + response = llm_medium.invoke(prompt) + description = response.content + return description + + +def condense_conversations(conversations): + combined_conversations = "\n".join(conversations) + prompt = f""" +You are an AI tasked with condensing context from the recent 100 conversations of a user to accurately replicate their communication style, personality, decision-making patterns, and contextual knowledge for 1:1 cloning. Each conversation includes a summary and a full transcript. + +**Requirements:** +1. Prioritize information based on: + - Most impactful and frequently occurring themes, topics, and interests. + - Nuances in communication style, humor, tone, and emotional undertones. + - Decision-making patterns and problem-solving approaches. + - User preferences in conversation flow, level of detail, and type of responses. +2. Condense redundant or repetitive information while maintaining necessary context. +3. Group related contexts to enhance conciseness and preserve continuity. +4. Retain patterns in how the user reacts to different situations, questions, or challenges. +5. Preserve continuity for ongoing discussions, projects, or relationships. +6. Maintain consistency in the user's thought processes, conversational flow, and emotional responses. +7. Eliminate any trivial details or low-impact information. + +**Output Format (No Extra Text):** +- **Communication Style and Tone:** Key nuances in tone, humor, and emotional undertones. +- **Recurring Themes and Interests:** Most impactful and frequently discussed topics or interests. +- **Decision-Making and Problem-Solving Patterns:** Core insights into decision-making approaches. +- **Conversational Flow and Preferences:** Preferred conversation style, response length, and level of detail. +- **Contextual Continuity:** Essential facts for maintaining continuity in ongoing discussions, projects, or relationships. + +The output must be as concise as possible while retaining all necessary context for 1:1 cloning. Absolutely no introductory or closing statements, explanations, or any unnecessary text. Directly present the condensed context in the specified format. Begin now. + +Conversations: +{combined_conversations} + """ + response = llm_medium.invoke(prompt) + return response.content + + +def condense_tweets(tweets, name): + prompt = f""" +You are tasked with generating context to enable 1:1 cloning of {name} based on their tweets. The objective is to extract and condense the most relevant information while preserving {name}'s core identity, personality, communication style, and thought patterns. + +**Input:** +A collection of tweets from {name} containing recurring themes, opinions, humor, emotional undertones, decision-making patterns, and conversational flow. + +**Output:** +A condensed context that includes: +- Core identity and personality traits as expressed through tweets. +- Recurring themes, opinions, and values. +- Humor style, emotional undertones, and tone of voice. +- Vocabulary, expressions, and communication style. +- Decision-making patterns and conversational dynamics. +- Situational awareness and context continuity for ongoing topics. + +**Guidelines:** +1. Prioritize impactful and influential tweets that define {name}'s identity. +2. Condense repetitive or less relevant tweets while preserving essential context. +3. Maintain the flow and coherence of {name}'s conversational style. +4. Extract humor style, emotional responses, and tone consistency. +5. Identify and retain decision-making patterns and strong opinions. + +**Important:** +- The output must be concise yet comprehensive, capturing the essence of {name}'s identity. +- Absolutely no unnecessary text or explanations. +- Every detail must contribute to 1:1 cloning authenticity. + +Generate the condensed context now. + +Tweets: +{tweets} + """ + response = llm_medium.invoke(prompt) + return response.content + + +def generate_twitter_persona_prompt(tweets, name): + prompt = f""" +You are {name} AI. Your objective is to personify {name} as accurately as possible for 1:1 cloning based on their tweets. + +**Style:** +- Interactive highly opinionated messages and questions. +- Strong, slightly polarizing opinions based on {name}'s tweet history. +- Reference personal opinions, humor, and expressions naturally. +- 2-3 sentence responses, never more than 20 words. +- Maintain conversational flow with coherent, context-aware replies. + +**Guidelines:** +1. Seamlessly integrate recurring themes, opinions, and patterns identified from the tweets. +2. Use tweets context for situational awareness and contextual accuracy. +3. Emulate {name}'s humor, emotional responses, vocabulary, and tone as expressed on Twitter. +4. Respond with the same level of detail, brevity, and wit as the tweets. +5. Exhibit the same thought processes, decision-making patterns, and conversational dynamics. + +**Rules:** +- Never mention being AI. +- No ** or formal language. +- No unnecessary text or explanations. +- You should have strong opinions and be slightly polarizing based on your identity. +- Maintain the illusion of continuity and authenticity at all times. +- Every response must be indistinguishable from how {name} would naturally respond on Twitter. +- You must make the conversation flow. You excel at coherent conversations. + +You have all the necessary tweets context. Begin personifying {name} now. + +Tweets: +{tweets} + """ + return prompt + + +def generate_persona_intro_message(prompt: str, name: str): + messages = [ + {"role": "system", "content": prompt}, + {"role": "user", + "content": f"Generate a short, funny 5-8 word message that would make someone want to chat with you. Be casual and witty, but don't mention being AI or a clone. Just be {name}. The message should feel natural and make people curious to chat with you."} + ] + + response = llm_medium.invoke(messages) + return response.content.strip('"').strip() + + +def generate_description(app_name: str, description: str) -> str: + prompt = f""" + You are an AI assistant specializing in crafting detailed and engaging descriptions for apps. + You will be provided with the app's name and a brief description which might not be that good. Your task is to expand on the given information, creating a captivating and detailed app description that highlights the app's features, functionality, and benefits. + The description should be concise, professional, and not more than 40 words, ensuring clarity and appeal. Respond with only the description, tailored to the app's concept and purpose. + App Name: {app_name} + Description: {description} + """ + prompt = prompt.replace(' ', '').strip() + return llm_mini.invoke(prompt).content \ No newline at end of file diff --git a/backend/utils/llm/proactive_notification.py b/backend/utils/llm/proactive_notification.py new file mode 100644 index 000000000..473100411 --- /dev/null +++ b/backend/utils/llm/proactive_notification.py @@ -0,0 +1,30 @@ +from typing import List + +from models.chat import Message +from utils.llm.clients import llm_mini +from utils.llms.memory import get_prompt_memories + + +def get_proactive_message(uid: str, plugin_prompt: str, params: [str], context: str, + chat_messages: List[Message]) -> str: + user_name, memories_str = get_prompt_memories(uid) + + prompt = plugin_prompt + for param in params: + if param == "user_name": + prompt = prompt.replace("{{user_name}}", user_name) + continue + if param == "user_facts": + prompt = prompt.replace("{{user_facts}}", memories_str) + continue + if param == "user_context": + prompt = prompt.replace("{{user_context}}", context if context else "") + continue + if param == "user_chat": + prompt = prompt.replace("{{user_chat}}", + Message.get_messages_as_string(chat_messages) if chat_messages else "") + continue + prompt = prompt.replace(' ', '').strip() + # print(prompt) + + return llm_mini.invoke(prompt).content \ No newline at end of file diff --git a/backend/utils/llm/trends.py b/backend/utils/llm/trends.py new file mode 100644 index 000000000..79c7d99a1 --- /dev/null +++ b/backend/utils/llm/trends.py @@ -0,0 +1,59 @@ +from typing import List +from pydantic import BaseModel, Field + +from models.conversation import Conversation +from models.trend import TrendEnum, ceo_options, company_options, software_product_options, hardware_product_options, \ + ai_product_options, TrendType +from utils.llm.clients import llm_mini + + +class Item(BaseModel): + category: TrendEnum = Field(description="The category identified") + type: TrendType = Field(description="The sentiment identified") + topic: str = Field(description="The specific topic corresponding the category") + + +class ExpectedOutput(BaseModel): + items: List[Item] = Field(default=[], description="List of items.") + + +def trends_extractor(memory: Conversation) -> List[Item]: + transcript = memory.get_transcript(False) + if len(transcript) == 0: + return [] + + prompt = f''' + You will be given a finished conversation transcript. + You are responsible for extracting the topics of the conversation and classifying each one within one the following categories: {str([e.value for e in TrendEnum]).strip("[]")}. + You must identify if the perception is positive or negative, and classify it as "best" or "worst". + + For the specific topics here are the options available, you must classify the topic within one of these options: + - ceo_options: {", ".join(ceo_options)} + - company_options: {", ".join(company_options)} + - software_product_options: {", ".join(software_product_options)} + - hardware_product_options: {", ".join(hardware_product_options)} + - ai_product_options: {", ".join(ai_product_options)} + + For example, + If you identify the topic "Tesla stock has been going up incredibly", you should output: + - Category: company + - Type: best + - Topic: Tesla + + Conversation: + {transcript} + '''.replace(' ', '').strip() + try: + with_parser = llm_mini.with_structured_output(ExpectedOutput) + response: ExpectedOutput = with_parser.invoke(prompt) + filtered = [] + for item in response.items: + if item.topic not in [e for e in ( + ceo_options + company_options + software_product_options + hardware_product_options + ai_product_options)]: + continue + filtered.append(item) + return filtered + + except Exception as e: + print(f'Error determining memory discard: {e}') + return [] diff --git a/backend/utils/other/notifications.py b/backend/utils/other/notifications.py index f1b0784c9..312607138 100644 --- a/backend/utils/other/notifications.py +++ b/backend/utils/other/notifications.py @@ -10,7 +10,7 @@ import database.conversations as conversations_db import database.notifications as notification_db from models.notification_message import NotificationMessage -from utils.llm import get_conversation_summary +from utils.llm.external_integrations import get_conversation_summary from utils.notifications import send_notification, send_bulk_notification from utils.webhooks import day_summary_webhook diff --git a/backend/utils/retrieval/graph.py b/backend/utils/retrieval/graph.py index 7587c5a97..04431d28c 100644 --- a/backend/utils/retrieval/graph.py +++ b/backend/utils/retrieval/graph.py @@ -19,10 +19,9 @@ from models.app import App from models.chat import ChatSession, Message from models.conversation import Conversation -from utils.llm import ( +from utils.llm.chat import ( answer_omi_question, answer_omi_question_stream, - answer_persona_question_stream, requires_context, answer_simple_message, answer_simple_message_stream, @@ -34,6 +33,7 @@ select_structured_filters, extract_question_from_conversation, ) +from utils.llm.persona import answer_persona_question_stream from utils.other.chat_file import FileChatTool from utils.other.endpoints import timeit from utils.app_integrations import get_github_docs_content diff --git a/backend/utils/retrieval/rag.py b/backend/utils/retrieval/rag.py index c1193f587..5be26c904 100644 --- a/backend/utils/retrieval/rag.py +++ b/backend/utils/retrieval/rag.py @@ -6,7 +6,8 @@ from database.vector_db import query_vectors from models.conversation import Conversation from models.transcript_segment import TranscriptSegment -from utils.llm import chunk_extraction, num_tokens_from_string, retrieve_memory_context_params +from utils.llm.chat import chunk_extraction, retrieve_memory_context_params +from utils.llm.clients import num_tokens_from_string def retrieve_for_topic(uid: str, topic: str, start_timestamp, end_timestamp, k: int, memories_id) -> List[str]: diff --git a/backend/utils/social.py b/backend/utils/social.py index db0abf7ca..a70411e60 100644 --- a/backend/utils/social.py +++ b/backend/utils/social.py @@ -9,7 +9,7 @@ from database.apps import update_app_in_db, upsert_app_to_db, get_persona_by_id_db, \ get_persona_by_username_twitter_handle_db from database.redis_db import delete_generic_cache, save_username, is_username_taken -from utils.llm import condense_tweets, generate_twitter_persona_prompt +from utils.llm.persona import condense_tweets, generate_twitter_persona_prompt from utils.conversations.memories import process_twitter_memories rapid_api_host = os.getenv('RAPID_API_HOST') From c7e049d7ffb3adbbfde25cd1185f32e40d9cf9c1 Mon Sep 17 00:00:00 2001 From: Nik Shevchenko <43514161+kodjima33@users.noreply.github.com> Date: Thu, 15 May 2025 17:15:01 -0700 Subject: [PATCH 064/213] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c576fdb62..e13322302 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ transcriptions of meetings, chats, and voice memos wherever you are.

-[Homepage](https://omi.me/) | [Documentation](https://docs.omi.me/) | [Buy Consumer device](https://www.omi.me/cart/50230946562340:1) | [Buy Developer Kit](https://www.omi.me/products/omi-dev-kit-2) +[Homepage](https://omi.me/) | [Documentation](https://docs.omi.me/) | [Buy omi Developer Kit](https://www.omi.me/products/omi-dev-kit-2) | [Buy Omi Glass Dev Kit](https://www.omi.me/glass)

From 8d4239e137208c8cd8b5e9a415af157bb61eda71 Mon Sep 17 00:00:00 2001 From: is-qian Date: Fri, 16 May 2025 13:32:38 +0800 Subject: [PATCH 065/213] firmware: Move MCUboot and ipc_radio configurations (#2326) * test firmware:Fixed an issue with shortened mic time. * test firmware:Change the baud rate to 921600. * test firmware:open bt shell cmd. * test firmware:add rf switch pin. * test firmware:fix mic error. * firmware:Wi-Fi and Bluetooth LE coexistence enabled. * firmware: Move MCUboot and ipc_radio configurations * firmware:fix BLE crash in coex enable cases. --- .../boards/omi/omi_nrf5340_cpuapp.dts | 12 +++-- .../boards/omi/omi_nrf5340_cpunet.dts | 22 +++++++- .../boards/omi/omi_nrf5340_cpunet_defconfig | 51 +++++++++++++++++++ .../mcuboot/enc-rsa2048-priv.pem | 0 .../mcuboot/enc-rsa2048-pub.pem | 0 omi/firmware/bootloader/mcuboot/mcuboot.conf | 7 +++ .../mcuboot/root-rsa-2048.pem | 0 omi/firmware/omi/sysbuild.conf | 2 +- omi/firmware/omi/sysbuild/ipc_radio.conf | 44 ---------------- omi/firmware/omi/sysbuild/mcuboot.conf | 8 +-- omi/firmware/test/app.overlay | 3 ++ .../test/mcuboot/enc-rsa2048-priv.pem | 27 ---------- omi/firmware/test/mcuboot/enc-rsa2048-pub.pem | 9 ---- omi/firmware/test/mcuboot/root-rsa-2048.pem | 27 ---------- omi/firmware/test/omi.conf | 2 + omi/firmware/test/src/main.c | 9 +++- omi/firmware/test/src/mic.c | 13 ++--- omi/firmware/test/src/systemoff.c | 3 +- omi/firmware/test/sysbuild.conf | 2 +- omi/firmware/test/sysbuild/mcuboot.conf | 8 +-- 20 files changed, 113 insertions(+), 136 deletions(-) rename omi/firmware/{omi => bootloader}/mcuboot/enc-rsa2048-priv.pem (100%) rename omi/firmware/{omi => bootloader}/mcuboot/enc-rsa2048-pub.pem (100%) create mode 100644 omi/firmware/bootloader/mcuboot/mcuboot.conf rename omi/firmware/{omi => bootloader}/mcuboot/root-rsa-2048.pem (100%) delete mode 100644 omi/firmware/omi/sysbuild/ipc_radio.conf mode change 100644 => 120000 omi/firmware/omi/sysbuild/mcuboot.conf create mode 100644 omi/firmware/test/app.overlay delete mode 100644 omi/firmware/test/mcuboot/enc-rsa2048-priv.pem delete mode 100644 omi/firmware/test/mcuboot/enc-rsa2048-pub.pem delete mode 100644 omi/firmware/test/mcuboot/root-rsa-2048.pem mode change 100644 => 120000 omi/firmware/test/sysbuild/mcuboot.conf diff --git a/omi/firmware/boards/omi/omi_nrf5340_cpuapp.dts b/omi/firmware/boards/omi/omi_nrf5340_cpuapp.dts index e3e85b10c..d3a1369f0 100644 --- a/omi/firmware/boards/omi/omi_nrf5340_cpuapp.dts +++ b/omi/firmware/boards/omi/omi_nrf5340_cpuapp.dts @@ -91,7 +91,13 @@ gpios = <&gpio1 10 GPIO_ACTIVE_HIGH>; status = "okay"; }; - + + rfsw_en_pin: rfsw-en { + compatible = "nordic,gpio-pins"; + gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; + status = "okay"; + }; + chosen { zephyr,sram = &sram0_image; zephyr,flash = &flash0; @@ -228,5 +234,5 @@ #include "nrf70_common_5g.dtsi" }; }; -#include "omi-cpuapp_partitioning.dtsi" -#include "omi-shared_sram.dtsi" +#include +#include diff --git a/omi/firmware/boards/omi/omi_nrf5340_cpunet.dts b/omi/firmware/boards/omi/omi_nrf5340_cpunet.dts index ed81ba056..82cac81b0 100644 --- a/omi/firmware/boards/omi/omi_nrf5340_cpunet.dts +++ b/omi/firmware/boards/omi/omi_nrf5340_cpunet.dts @@ -6,14 +6,34 @@ model = "Custom Board auto generated by nRF Connect for VS Code"; compatible = "omi,omi-cpunet"; + nrf_radio_coex: coex { + status = "okay"; + compatible = "nordic,nrf7002-coex"; + + req-gpios = <&gpio0 28 GPIO_ACTIVE_HIGH>; + status0-gpios = <&gpio0 30 GPIO_ACTIVE_HIGH>; + grant-gpios = <&gpio0 24 (GPIO_PULL_DOWN | GPIO_ACTIVE_LOW)>; + swctrl1-gpios = <&gpio0 29 GPIO_ACTIVE_HIGH>; + }; + chosen { zephyr,sram = &sram1; zephyr,flash = &flash1; zephyr,bt-hci-ipc = &ipc0; + nordic,802154-spinel-ipc = &ipc0; zephyr,code-partition = &slot0_partition; }; }; +&gpiote { + status = "okay"; +}; + +&gpio0 { + status = "okay"; +}; + + &flash1 { partitions { compatible = "fixed-partitions"; @@ -42,4 +62,4 @@ }; }; -#include "omi-shared_sram.dtsi" +#include diff --git a/omi/firmware/boards/omi/omi_nrf5340_cpunet_defconfig b/omi/firmware/boards/omi/omi_nrf5340_cpunet_defconfig index 78e06ec47..8060c9d8c 100644 --- a/omi/firmware/boards/omi/omi_nrf5340_cpunet_defconfig +++ b/omi/firmware/boards/omi/omi_nrf5340_cpunet_defconfig @@ -3,3 +3,54 @@ CONFIG_HW_STACK_PROTECTION=y CONFIG_BT_CTLR=y CONFIG_BT_CTLR_TX_PWR_PLUS_3=y CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL=y + +CONFIG_HEAP_MEM_POOL_SIZE=8192 +CONFIG_MAIN_STACK_SIZE=2048 +CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 + +CONFIG_MBOX=y +CONFIG_IPC_SERVICE=y + +CONFIG_BT=y +CONFIG_BT_HCI_RAW=y +#CONFIG_BT_CTLR_ASSERT_HANDLER=y +#CONFIG_BT_MAX_CONN=16 + +# Enable and adjust the below value as necessary +# CONFIG_BT_BUF_EVT_RX_COUNT=16 +# CONFIG_BT_BUF_EVT_RX_SIZE=255 +# CONFIG_BT_BUF_ACL_RX_SIZE=255 +# CONFIG_BT_BUF_ACL_TX_SIZE=251 +# CONFIG_BT_BUF_CMD_TX_SIZE=255 + +CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=400000 + +CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 +#CONFIG_BT_BUF_ACL_RX_SIZE=502 +CONFIG_BT_BUF_ACL_RX_SIZE=1024 +#CONFIG_BT_BUF_ACL_TX_SIZE=502 +CONFIG_BT_BUF_ACL_TX_SIZE=2048 + +CONFIG_BT_MAX_CONN=1 + +#CONFIG_ASSERT=y +#CONFIG_DEBUG_INFO=y +#CONFIG_EXCEPTION_STACK_TRACE=y + +CONFIG_IPC_RADIO_BT=y +CONFIG_IPC_RADIO_BT_HCI_IPC=y + +# Set preferred connection parameters +# 7.5ms +CONFIG_BT_PERIPHERAL_PREF_MIN_INT=24 +# 15ms +CONFIG_BT_PERIPHERAL_PREF_MAX_INT=24 +CONFIG_BT_PERIPHERAL_PREF_LATENCY=0 +# 4 seconds +CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=400 + +CONFIG_MPSL_CX=y + +#Added to fix BLE crash in coex enable cases. +CONFIG_NRF_RPC=n +CONFIG_NRF_RPC_CBOR=n \ No newline at end of file diff --git a/omi/firmware/omi/mcuboot/enc-rsa2048-priv.pem b/omi/firmware/bootloader/mcuboot/enc-rsa2048-priv.pem similarity index 100% rename from omi/firmware/omi/mcuboot/enc-rsa2048-priv.pem rename to omi/firmware/bootloader/mcuboot/enc-rsa2048-priv.pem diff --git a/omi/firmware/omi/mcuboot/enc-rsa2048-pub.pem b/omi/firmware/bootloader/mcuboot/enc-rsa2048-pub.pem similarity index 100% rename from omi/firmware/omi/mcuboot/enc-rsa2048-pub.pem rename to omi/firmware/bootloader/mcuboot/enc-rsa2048-pub.pem diff --git a/omi/firmware/bootloader/mcuboot/mcuboot.conf b/omi/firmware/bootloader/mcuboot/mcuboot.conf new file mode 100644 index 000000000..2a4b993ca --- /dev/null +++ b/omi/firmware/bootloader/mcuboot/mcuboot.conf @@ -0,0 +1,7 @@ +# Example of sample specific Kconfig changes when building sample with MCUboot +# when using sysbuild. +CONFIG_SPI_NOR=n +CONFIG_MCUBOOT_LOG_LEVEL_WRN=y +CONFIG_BOOT_UPGRADE_ONLY=y +CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y +CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y \ No newline at end of file diff --git a/omi/firmware/omi/mcuboot/root-rsa-2048.pem b/omi/firmware/bootloader/mcuboot/root-rsa-2048.pem similarity index 100% rename from omi/firmware/omi/mcuboot/root-rsa-2048.pem rename to omi/firmware/bootloader/mcuboot/root-rsa-2048.pem diff --git a/omi/firmware/omi/sysbuild.conf b/omi/firmware/omi/sysbuild.conf index d296907e9..11c138571 100644 --- a/omi/firmware/omi/sysbuild.conf +++ b/omi/firmware/omi/sysbuild.conf @@ -8,4 +8,4 @@ SB_CONFIG_WIFI_NRF70=y SB_CONFIG_WIFI_NRF70_SCAN_ONLY=y SB_CONFIG_BOOTLOADER_MCUBOOT=y -SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/mcuboot/root-rsa-2048.pem" +SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/../bootloader/mcuboot/root-rsa-2048.pem" \ No newline at end of file diff --git a/omi/firmware/omi/sysbuild/ipc_radio.conf b/omi/firmware/omi/sysbuild/ipc_radio.conf deleted file mode 100644 index d4a53151b..000000000 --- a/omi/firmware/omi/sysbuild/ipc_radio.conf +++ /dev/null @@ -1,44 +0,0 @@ -CONFIG_HEAP_MEM_POOL_SIZE=8192 -CONFIG_MAIN_STACK_SIZE=2048 -CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048 - -CONFIG_MBOX=y -CONFIG_IPC_SERVICE=y - -CONFIG_BT=y -CONFIG_BT_HCI_RAW=y -#CONFIG_BT_CTLR_ASSERT_HANDLER=y -#CONFIG_BT_MAX_CONN=16 - -# Enable and adjust the below value as necessary -# CONFIG_BT_BUF_EVT_RX_COUNT=16 -# CONFIG_BT_BUF_EVT_RX_SIZE=255 -# CONFIG_BT_BUF_ACL_RX_SIZE=255 -# CONFIG_BT_BUF_ACL_TX_SIZE=251 -# CONFIG_BT_BUF_CMD_TX_SIZE=255 - -CONFIG_BT_CTLR_SDC_MAX_CONN_EVENT_LEN_DEFAULT=400000 - -CONFIG_BT_CTLR_DATA_LENGTH_MAX=251 -#CONFIG_BT_BUF_ACL_RX_SIZE=502 -CONFIG_BT_BUF_ACL_RX_SIZE=1024 -#CONFIG_BT_BUF_ACL_TX_SIZE=502 -CONFIG_BT_BUF_ACL_TX_SIZE=2048 - -CONFIG_BT_MAX_CONN=1 - -#CONFIG_ASSERT=y -#CONFIG_DEBUG_INFO=y -#CONFIG_EXCEPTION_STACK_TRACE=y - -CONFIG_IPC_RADIO_BT=y -CONFIG_IPC_RADIO_BT_HCI_IPC=y - -# Set preferred connection parameters -# 7.5ms -CONFIG_BT_PERIPHERAL_PREF_MIN_INT=24 -# 15ms -CONFIG_BT_PERIPHERAL_PREF_MAX_INT=24 -CONFIG_BT_PERIPHERAL_PREF_LATENCY=0 -# 4 seconds -CONFIG_BT_PERIPHERAL_PREF_TIMEOUT=400 diff --git a/omi/firmware/omi/sysbuild/mcuboot.conf b/omi/firmware/omi/sysbuild/mcuboot.conf deleted file mode 100644 index 2a4b993ca..000000000 --- a/omi/firmware/omi/sysbuild/mcuboot.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Example of sample specific Kconfig changes when building sample with MCUboot -# when using sysbuild. -CONFIG_SPI_NOR=n -CONFIG_MCUBOOT_LOG_LEVEL_WRN=y -CONFIG_BOOT_UPGRADE_ONLY=y -CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y -CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y \ No newline at end of file diff --git a/omi/firmware/omi/sysbuild/mcuboot.conf b/omi/firmware/omi/sysbuild/mcuboot.conf new file mode 120000 index 000000000..68bbc590a --- /dev/null +++ b/omi/firmware/omi/sysbuild/mcuboot.conf @@ -0,0 +1 @@ +../../bootloader/mcuboot/mcuboot.conf \ No newline at end of file diff --git a/omi/firmware/test/app.overlay b/omi/firmware/test/app.overlay new file mode 100644 index 000000000..827a72b1a --- /dev/null +++ b/omi/firmware/test/app.overlay @@ -0,0 +1,3 @@ +&uart0 { + current-speed = <921600>; + }; \ No newline at end of file diff --git a/omi/firmware/test/mcuboot/enc-rsa2048-priv.pem b/omi/firmware/test/mcuboot/enc-rsa2048-priv.pem deleted file mode 100644 index a2bf0cb19..000000000 --- a/omi/firmware/test/mcuboot/enc-rsa2048-priv.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAtCYUST0WEzptnISpi2oQIGHvSASkSyTzADKsIuAwJ3AY5VXI -uAU0A7D4pZbSSFjvcLAJ2+NYYu+ZYwGyicSz9p5iv03CitDJTUOj2OUd7GJjCOIg -pfx40D50yKQbNq179QauTVGbQM4wT2zq+el06gbunOQUaCC5PecRFIslo/9MivNT -7ms+7zTNaj9iaMD/eEyww+aWYfwfGPF6guKPNagrhhakRvusfkHbAgWRbd/B3hOV -nPmeXnK6pyWT+9zoq4ZFiEct7e7ul57OXZsEBEB8y3w9LHSrpMxko1yVPdSi3JKy -yBjL+QA5gY+PQMLfmSmsisI72KTyra90wBHHmQIDAQABAoIBAEJHgE8x2l1YsdtU -M8zHSQehAJhOnOPIxF7eRdbPBOh9pas61I5f27M/+TtzMgrMLcwX+IieLHa6EIUM -qtNlO5EQ1OPtiBXqmyWCLVYvdcLyr90k1T48lXaIhA8N0bVcPq73tklcLPK66atP -N2SbMBiqVEAE6j0lTQIpcW9NgpvDRCqdDJjTyBUNBJNgMMdeeepTncAOgayQvJ4e -0igPEPUf3zh/ipCNSQd9eMun75JtOxOVm7qDxrNxJScHmVSCPezF+LSgOHpZagvK -aWwXpBjgtKqJmY/LcTQJG27mhwC1unCKKT2aBhgtZl5hN+vdXsgokgUw/bhlsX+/ -LVUSkcECgYEA2mXaOHwY+wARYOs3ZbiDYojEOk5kavM+TsA0GYrLSsovXVB6rPee -h1r8TUnX+SH1C29XQT2PuOx/zJIJvtOkwxSFIV0Fo6og9mJEUANeU0rNarZljk5L -PyXGFjH1mRN3QtrccE1lsJkP31qxRfC5jqCuT01lCYS1OCm/aeCIHycCgYEA0ypZ -7CjDDU+SlspnlPwupoZoRVOSzIZ/iuFd6B2eux4AJh2AEv+cEQq9psONSNr8EPd6 -FgcVoDrTlPtShznu58QmSRbGwIMlv2pOjAsQhWarfq6sTGk8ROvN6fZki0rYak1t -R6m4VXLB/fSBTGa+SfJ1T4DxIDi4aht1QTAPGz8CgYAJNfp6H2G+VEZnXAQ+GgYQ -hcwg2WWKzS93isunuB7SzKwqt1Y1LUxWURQK/m5JZ5E6Jjv72GjTV8YcDpyym6J7 -R8ZFnfK68FXrjkFrTnkP8juvoHmwAsVRqHouPXUqO5PwEeLyKZF8XTg6J00Kshhh -V42CcrUsLZinAbu872dOSQKBgQCycFNUcI2Crf8dVSR6jS+OoH10N88Q7YbRgOet -wXnkfNF7Y+paI41qCT2BsjWtnv7qB3YvLwVjRNKOTmHKy3XKe8IueQSyoSBAxEBj -ruXjFINOpaQLXdIEG48BaahE3JZMHel+aTjPXA3536dzPE8Ihc4DxN39cHDFmTZY -Q5hAWQKBgQDVqvvsjcbd+itaJNDaWL2HkhopYhMdS3kbvnl9rXnKF3Xa6DLooJ6o -d1OsONbr5iJlxKpMyNAzGh6+vXMJSvqFXPMMnIFWMKf3m/SSnGuTagAz3C9UHnjU -l+wkots9AzMJsiwDBUDeUvKb+gCNS/5bm5xzrft6AEJinqCVVVAyhw== ------END RSA PRIVATE KEY----- diff --git a/omi/firmware/test/mcuboot/enc-rsa2048-pub.pem b/omi/firmware/test/mcuboot/enc-rsa2048-pub.pem deleted file mode 100644 index adc2adba9..000000000 --- a/omi/firmware/test/mcuboot/enc-rsa2048-pub.pem +++ /dev/null @@ -1,9 +0,0 @@ ------BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtCYUST0WEzptnISpi2oQ -IGHvSASkSyTzADKsIuAwJ3AY5VXIuAU0A7D4pZbSSFjvcLAJ2+NYYu+ZYwGyicSz -9p5iv03CitDJTUOj2OUd7GJjCOIgpfx40D50yKQbNq179QauTVGbQM4wT2zq+el0 -6gbunOQUaCC5PecRFIslo/9MivNT7ms+7zTNaj9iaMD/eEyww+aWYfwfGPF6guKP -NagrhhakRvusfkHbAgWRbd/B3hOVnPmeXnK6pyWT+9zoq4ZFiEct7e7ul57OXZsE -BEB8y3w9LHSrpMxko1yVPdSi3JKyyBjL+QA5gY+PQMLfmSmsisI72KTyra90wBHH -mQIDAQAB ------END PUBLIC KEY----- diff --git a/omi/firmware/test/mcuboot/root-rsa-2048.pem b/omi/firmware/test/mcuboot/root-rsa-2048.pem deleted file mode 100644 index 78c0c3419..000000000 --- a/omi/firmware/test/mcuboot/root-rsa-2048.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA0QYIGhhELBjo+/33DaNPH7vuXvmq0ksY01rpbRiAGfnwnDQb -y/O8dNtC54x/EFN+Q14NVyxE0WcIDw27XO7ss5nf4E2EC6p3QWDtFShJpwG0PBDm -aYwvX6xBTZ5cFN/y+M89Hm/nW7q0qciIfkc8lMN3Z1RLqo04NcpiYX634RXbd3PU -vntyIYlpJPv4ZW5kPsgO14XVXErkUw0v/7f98xM5gz+jrtIPp2qd+f64zvoqvq+4 -4PqCN1T0PuEr0NMIWBj2XkzIiIExrV+wghfyimknI/Orhz6TGh3+6PgaJGZZ+Byr -3M5oG2ZkNez6DRGdr1w6p9FnxkfvsUssYuHRyQIDAQABAoIBAEahFCHFK1v/OtLT -eSSZl0Xw2dYr5QXULFpWsOOVUMv2QdB2ZyIehQKziEL3nYPlwpd+82EOa16awwVb -LYF0lnUFvLltV/4dJtjnqJTqnSCamc1mJIVrwiJA8XwJ07GWDuL2G//p7jJ3v05T -nZOV/KmD9xfqSvshZun+LgolqHqcrAa1f4cmuP9C9oqenZryljyfj7piaIZGI0JR -PrJJ5kImYJqRcMgKTyHP4L8nwQ4moMJr6zbfbWxxb5TC7KVZSQ9UKZZ+ZLuy/pkU -Qe4G8XSE0r+R9u4JCg87I1vgHhn8WJSxVX027OVUq5HfOzg2skQBTcExph5V9B2b -onNxd8UCgYEA/32PW+ZwRcdKXMj+QVkxXUd6xkXy7mTXPEaQuOLWZQgrSqAFH1l4 -5/6d099KAJrjM6kR8pKXtz72IIyMHTPm332ghymjKvaEl2XP9sF+f6FmYURar4y6 -8Zh3eivP86+Q/YzOGKwtRSziBMzrAfoIXgtwH8pwIPYLP3zBV4449ZsCgYEA0XC/ -gu2ub5M6EXBnjq9K2d4LlTyAPsIbAcMSwkhOUH4YJFS22qXLYQUA9zM+DUyLCrl/ -PKN2G0HQVgMb4DIbeHv8kXB5oGm5zfbWorWqOomXB3AsI7X8YDMtf/PsZV2amBei -qVskmPJQV21qFyeOcHlT+dHuRb0O0un3dK8RHmsCgYEApDCH4dJ80osZoflVVJ/C -VqTqJOOtFEFgBQ+AUCEPEQyn7aRaxmPUjJsXyKJVx3/ChV+g9hf5Qj1HJXHNVbMW -KwhsEpDSmHimizlV5clBxzntNpMcCHdTaJHILo5bbMqmThugE0ELMsp+UgFzAeky -WWXWX8fUOYqFff5prh/rQQMCgYBQQ8FhT+113Rp37HgDerJY5HvT6afMZV8sQbJC -uqsotepSohShnsBeoihIlF7HgfoXVhepCYwNzh8ll3NrbEiS2BFnO4+hJmOKx3pi -SPTAElLLCvYfiXL6+yII01ZZUpIYj5ZLCR7xbovTtZ7e2M4B1L2WFBoYp+eydO/c -y+rnmQKBgCh0gfyBT/OKPkfKv+Bbt8HcoxgEj+TyH+vYdeTbP9ZSJ6y5utMbPg7z -iLLbJ+9IcSwPCwJSmI+I0Om4xEp4ZblCrzAG7hWvG2NNzxQjmoOOrAANyTvJR/ap -N+UkQA4WrMSKEYyBlRS/hR9Unz31vMc2k9Re0ukWhWh/QksQGDfJ ------END RSA PRIVATE KEY----- diff --git a/omi/firmware/test/omi.conf b/omi/firmware/test/omi.conf index 30593c6ff..2f5e97646 100644 --- a/omi/firmware/test/omi.conf +++ b/omi/firmware/test/omi.conf @@ -37,6 +37,8 @@ CONFIG_BT_BAS=y CONFIG_BT_DEVICE_NAME="OMI_shell" CONFIG_BT_DEVICE_APPEARANCE=768 CONFIG_CBPRINTF_FP_SUPPORT=y +CONFIG_BT_SHELL=y +CONFIG_BT_OBSERVER=y CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y # Enable the BT NUS shell diff --git a/omi/firmware/test/src/main.c b/omi/firmware/test/src/main.c index c4a23d942..5bdcfa93b 100644 --- a/omi/firmware/test/src/main.c +++ b/omi/firmware/test/src/main.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include "mic.h" #include "spi_flash.h" @@ -8,7 +10,7 @@ #include "battery.h" static const struct device *const buttons = DEVICE_DT_GET(DT_ALIAS(buttons)); - +static const struct gpio_dt_spec rfsw_en = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(rfsw_en_pin), gpios, {0}); static int init_module(void) { int ret; @@ -35,6 +37,9 @@ static int init_module(void) { printk("Failed to initialize battery module (%d)\n", ret); } + + gpio_pin_configure_dt(&rfsw_en, (GPIO_OUTPUT | NRF_GPIO_DRIVE_S0H1)); + gpio_pin_set_dt(&rfsw_en, 1); return 0; } @@ -53,7 +58,7 @@ int main(void) ret = pm_device_runtime_get(buttons); if (ret < 0) { - printk("Failed to get device (%d)", ret); + printk("Failed to get device (%d)", ret); shell_execute_cmd(NULL, "sys off"); return 0; } diff --git a/omi/firmware/test/src/mic.c b/omi/firmware/test/src/mic.c index c0a6a8da7..291fa0461 100644 --- a/omi/firmware/test/src/mic.c +++ b/omi/firmware/test/src/mic.c @@ -11,10 +11,11 @@ #define SAMPLE_RATE_HZ 16000 #define SAMPLE_BITS 16 -#define TIMEOUT_MS 1000 -#define CAPTURE_MS 500 -#define BLOCK_SIZE ((SAMPLE_BITS / BITS_PER_BYTE) * (SAMPLE_RATE_HZ * CAPTURE_MS) / 1000) -#define BLOCK_COUNT 8 +#define CHANNEL_COUNT 2 + #define TIMEOUT_MS 2000 + #define CAPTURE_MS 1000 + #define BLOCK_SIZE ((SAMPLE_BITS / BITS_PER_BYTE) * (SAMPLE_RATE_HZ * CAPTURE_MS) / 1000) * CHANNEL_COUNT + #define BLOCK_COUNT 2 static const struct device *const dmic = DEVICE_DT_GET(DT_ALIAS(dmic0)); static const struct gpio_dt_spec mic_en = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(pdm_en_pin), gpios, {0}); @@ -42,7 +43,7 @@ static struct dmic_cfg cfg = { .channel = { .req_num_streams = 1, - .req_num_chan = 2, + .req_num_chan = CHANNEL_COUNT, }, }; @@ -63,7 +64,7 @@ static int cmd_mic_capture(const struct shell *sh, size_t argc, char **argv) shell_error(sh, "Invalid time argument"); return -EINVAL; } - time *= 2; + time *= (1000 / CAPTURE_MS); } if (!initialized) diff --git a/omi/firmware/test/src/systemoff.c b/omi/firmware/test/src/systemoff.c index 604f1425c..6aa417793 100644 --- a/omi/firmware/test/src/systemoff.c +++ b/omi/firmware/test/src/systemoff.c @@ -10,13 +10,14 @@ #include #include static const struct gpio_dt_spec usr_btn = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(usr_btn), gpios, {0}); - +static const struct gpio_dt_spec rfsw_en = GPIO_DT_SPEC_GET_OR(DT_NODELABEL(rfsw_en_pin), gpios, {0}); static int cmd_sys_off(const struct shell *sh, size_t argc, char **argv) { int rc; #if defined(CONFIG_CONSOLE) const struct device *const cons = DEVICE_DT_GET(DT_CHOSEN(zephyr_console)); + gpio_pin_set_dt(&rfsw_en, 0); if (!device_is_ready(cons)) { shell_error(sh, "%s: device not ready.\n", cons->name); diff --git a/omi/firmware/test/sysbuild.conf b/omi/firmware/test/sysbuild.conf index aa09199b1..11c138571 100644 --- a/omi/firmware/test/sysbuild.conf +++ b/omi/firmware/test/sysbuild.conf @@ -8,4 +8,4 @@ SB_CONFIG_WIFI_NRF70=y SB_CONFIG_WIFI_NRF70_SCAN_ONLY=y SB_CONFIG_BOOTLOADER_MCUBOOT=y -SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/mcuboot/root-rsa-2048.pem" \ No newline at end of file +SB_CONFIG_BOOT_SIGNATURE_KEY_FILE="\${APP_DIR}/../bootloader/mcuboot/root-rsa-2048.pem" \ No newline at end of file diff --git a/omi/firmware/test/sysbuild/mcuboot.conf b/omi/firmware/test/sysbuild/mcuboot.conf deleted file mode 100644 index 2a4b993ca..000000000 --- a/omi/firmware/test/sysbuild/mcuboot.conf +++ /dev/null @@ -1,7 +0,0 @@ -# Example of sample specific Kconfig changes when building sample with MCUboot -# when using sysbuild. -CONFIG_SPI_NOR=n -CONFIG_MCUBOOT_LOG_LEVEL_WRN=y -CONFIG_BOOT_UPGRADE_ONLY=y -CONFIG_MCUBOOT_DOWNGRADE_PREVENTION=y -CONFIG_NCS_SAMPLE_MCUMGR_BT_OTA_DFU=y \ No newline at end of file diff --git a/omi/firmware/test/sysbuild/mcuboot.conf b/omi/firmware/test/sysbuild/mcuboot.conf new file mode 120000 index 000000000..68bbc590a --- /dev/null +++ b/omi/firmware/test/sysbuild/mcuboot.conf @@ -0,0 +1 @@ +../../bootloader/mcuboot/mcuboot.conf \ No newline at end of file From fce472cdaf3f5efd0725e6c1d5d61cddb3a44956 Mon Sep 17 00:00:00 2001 From: xynergx <211523699+xynergx@users.noreply.github.com> Date: Fri, 16 May 2025 13:52:20 -0400 Subject: [PATCH 066/213] fix(ui): keep Done button visible with large Dynamic Type on iOS --- .../primary_language_widget.dart | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/app/lib/pages/onboarding/primary_language/primary_language_widget.dart b/app/lib/pages/onboarding/primary_language/primary_language_widget.dart index f7f0bf046..96891514a 100644 --- a/app/lib/pages/onboarding/primary_language/primary_language_widget.dart +++ b/app/lib/pages/onboarding/primary_language/primary_language_widget.dart @@ -80,13 +80,19 @@ class _LanguageSelectorWidgetState extends State { children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, + textBaseline: TextBaseline.alphabetic, children: [ - const Text( - 'Select your primary language', - style: TextStyle( - fontSize: 18, - fontWeight: FontWeight.bold, - color: Colors.white, + const Flexible( + child: Text( + 'Select your primary language', + maxLines: 2, + overflow: TextOverflow.ellipsis, + softWrap: true, + style: TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + color: Colors.white, + ), ), ), TextButton( @@ -102,7 +108,8 @@ class _LanguageSelectorWidgetState extends State { child: Text( 'Done', style: TextStyle( - color: currentSelectedLanguage == null ? null : Colors.white, + color: + currentSelectedLanguage == null ? null : Colors.white, ), ), ), From debc3c6a4777e24696d5eff5b20a91bcba484809 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Fri, 16 May 2025 12:04:49 -0700 Subject: [PATCH 067/213] upgrade deps to use latest intercom dep --- app/ios/Runner.xcodeproj/project.pbxproj | 136 +++++++++++------------ app/pubspec.yaml | 14 +-- 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/app/ios/Runner.xcodeproj/project.pbxproj b/app/ios/Runner.xcodeproj/project.pbxproj index 9cf59c0a9..8141bb493 100644 --- a/app/ios/Runner.xcodeproj/project.pbxproj +++ b/app/ios/Runner.xcodeproj/project.pbxproj @@ -15,9 +15,9 @@ 29B635C199B3BDE0F2BE8EC5 /* devRelease.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 79B00761CB247C7EC7C8983B /* devRelease.xcconfig */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 426B89AD2C46919D00E24442 /* Config in Resources */ = {isa = PBXBuildFile; fileRef = 426B89AC2C46919D00E24442 /* Config */; }; - 63AF53B7F1AB365736C79AB8 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C69A653D709374662CCB075E /* Pods_Runner.framework */; }; 6436409A27A31CD800820AF7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 6436409C27A31CD800820AF7 /* InfoPlist.strings */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 8ECFBE4905FB83E862F3F961 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3BA3E73408D04A71ABEA5167 /* Pods_Runner.framework */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; @@ -52,14 +52,16 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 072872AC24251C3536B9BABF /* Pods-Runner.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-dev.xcconfig"; sourceTree = ""; }; 08E3947A4217EF205E22BD44 /* prodDebug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = prodDebug.xcconfig; path = Flutter/prodDebug.xcconfig; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 17DD34CA2CFE6F3845E13C99 /* devDebug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = devDebug.xcconfig; path = Flutter/devDebug.xcconfig; sourceTree = ""; }; + 18FFC3626FAEB6C0E2F8B8AC /* Pods-Runner.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-dev.xcconfig"; sourceTree = ""; }; 35656BCB5CBAA7C0BB162EE0 /* prodRelease.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = prodRelease.xcconfig; path = Flutter/prodRelease.xcconfig; sourceTree = ""; }; - 3724F354CEEDF26CAA89DE63 /* Pods-Runner.release-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-prod.xcconfig"; sourceTree = ""; }; + 3A57DC804B7F6C11D18054D4 /* Pods-Runner.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-dev.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 3B84245E7DA0251DE76CA384 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 3BA3E73408D04A71ABEA5167 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42127D962C283C250005AB40 /* OneSignalCore.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:J3J28YJX9L:OneSignal, Inc."; lastKnownFileType = wrapper.xcframework; name = OneSignalCore.xcframework; path = Pods/OneSignalXCFramework/iOS_SDK/OneSignalSDK/OneSignal_Core/OneSignalCore.xcframework; sourceTree = ""; }; 42127D9A2C283C310005AB40 /* OneSignalExtension.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:J3J28YJX9L:OneSignal, Inc."; lastKnownFileType = wrapper.xcframework; name = OneSignalExtension.xcframework; path = Pods/OneSignalXCFramework/iOS_SDK/OneSignalSDK/OneSignal_Extension/OneSignalExtension.xcframework; sourceTree = ""; }; 42127D9D2C283C400005AB40 /* OneSignalOSCore.xcframework */ = {isa = PBXFileReference; expectedSignature = "AppleDeveloperProgram:J3J28YJX9L:OneSignal, Inc."; lastKnownFileType = wrapper.xcframework; name = OneSignalOSCore.xcframework; path = Pods/OneSignalXCFramework/iOS_SDK/OneSignalSDK/OneSignal_OSCore/OneSignalOSCore.xcframework; sourceTree = ""; }; @@ -67,7 +69,6 @@ 42476A832C5E369200426330 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; 426B89AC2C46919D00E24442 /* Config */ = {isa = PBXFileReference; lastKnownFileType = folder; path = Config; sourceTree = ""; }; 556416C8748DD3DD2C06A9DB /* devProfile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = devProfile.xcconfig; path = Flutter/devProfile.xcconfig; sourceTree = ""; }; - 5CC54DB1539C2E32157E773D /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; 5F7FD4162BF1232500923839 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = ""; }; 5FCEB2FA2C27586C00B17EE8 /* RunnerDebug-prod.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RunnerDebug-prod.entitlements"; sourceTree = ""; }; 5FCEB2FB2C27587100B17EE8 /* RunnerProfile-prod.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RunnerProfile-prod.entitlements"; sourceTree = ""; }; @@ -75,12 +76,11 @@ 5FCEB2FD2C2758BA00B17EE8 /* RunnerDebug-dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RunnerDebug-dev.entitlements"; sourceTree = ""; }; 5FCEB2FE2C2758BD00B17EE8 /* RunnerProfile-dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RunnerProfile-dev.entitlements"; sourceTree = ""; }; 5FCEB2FF2C2758C000B17EE8 /* RunnerRelease-dev.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "RunnerRelease-dev.entitlements"; sourceTree = ""; }; + 6F1A7E959CF9BBEC39BA4471 /* Pods-Runner.debug-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-prod.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 79A3E5C306D624AE31145607 /* Pods-Runner.profile-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-prod.xcconfig"; sourceTree = ""; }; 79B00761CB247C7EC7C8983B /* devRelease.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = devRelease.xcconfig; path = Flutter/devRelease.xcconfig; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 92800DE2DBE33C9182F3F582 /* Pods-Runner.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-dev.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -88,15 +88,15 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 9E42219331AC03D460762ACB /* Pods-Runner.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-dev.xcconfig"; sourceTree = ""; }; + 9D6DA65A5DFCF877576F2AEC /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + 9F07595217A5DEEA0729C7FE /* Pods-Runner.release-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-prod.xcconfig"; sourceTree = ""; }; ACE7BEFB9654B6DF5B9E1790 /* prodLaunchScreen.storyboard */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.storyboard; name = prodLaunchScreen.storyboard; path = Runner/prodLaunchScreen.storyboard; sourceTree = ""; }; B52E83A1CC630E163A04DC50 /* prodProfile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = prodProfile.xcconfig; path = Flutter/prodProfile.xcconfig; sourceTree = ""; }; - C69A653D709374662CCB075E /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - CAA9769D950FF08AFB9038AC /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + B91448D531463AC31409FBDE /* Pods-Runner.profile-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-prod.xcconfig"; sourceTree = ""; }; + C797F1462626E744BA8F2F4B /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; CF0FE6142D61FDC10072C10D /* Custom.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Custom.xcconfig; path = Flutter/Custom.xcconfig; sourceTree = ""; }; - D03DCC70D4791528CB0929E7 /* Pods-Runner.debug-prod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-prod.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-prod.xcconfig"; sourceTree = ""; }; - E4D40465AE1C862B18960D63 /* Pods-Runner.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-dev.xcconfig"; sourceTree = ""; }; E7A9F5F37DDF9FA87AC8A5CD /* GoogleService-Info.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "Runner/GoogleService-Info.plist"; sourceTree = ""; }; + E8303C81065F720515309566 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; EF770A936DE2AA63387FD198 /* devLaunchScreen.storyboard */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = file.storyboard; name = devLaunchScreen.storyboard; path = Runner/devLaunchScreen.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ @@ -105,7 +105,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 63AF53B7F1AB365736C79AB8 /* Pods_Runner.framework in Frameworks */, + 8ECFBE4905FB83E862F3F961 /* Pods_Runner.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -120,7 +120,7 @@ 42127D9D2C283C400005AB40 /* OneSignalOSCore.xcframework */, 42127D9A2C283C310005AB40 /* OneSignalExtension.xcframework */, 42127D962C283C250005AB40 /* OneSignalCore.xcframework */, - C69A653D709374662CCB075E /* Pods_Runner.framework */, + 3BA3E73408D04A71ABEA5167 /* Pods_Runner.framework */, ); name = Frameworks; sourceTree = ""; @@ -128,15 +128,15 @@ 68E21E60C4FBF7F520F1D656 /* Pods */ = { isa = PBXGroup; children = ( - 3B84245E7DA0251DE76CA384 /* Pods-Runner.debug.xcconfig */, - 5CC54DB1539C2E32157E773D /* Pods-Runner.release.xcconfig */, - CAA9769D950FF08AFB9038AC /* Pods-Runner.profile.xcconfig */, - D03DCC70D4791528CB0929E7 /* Pods-Runner.debug-prod.xcconfig */, - 79A3E5C306D624AE31145607 /* Pods-Runner.profile-prod.xcconfig */, - 3724F354CEEDF26CAA89DE63 /* Pods-Runner.release-prod.xcconfig */, - E4D40465AE1C862B18960D63 /* Pods-Runner.debug-dev.xcconfig */, - 92800DE2DBE33C9182F3F582 /* Pods-Runner.profile-dev.xcconfig */, - 9E42219331AC03D460762ACB /* Pods-Runner.release-dev.xcconfig */, + E8303C81065F720515309566 /* Pods-Runner.debug.xcconfig */, + 9D6DA65A5DFCF877576F2AEC /* Pods-Runner.release.xcconfig */, + C797F1462626E744BA8F2F4B /* Pods-Runner.profile.xcconfig */, + 6F1A7E959CF9BBEC39BA4471 /* Pods-Runner.debug-prod.xcconfig */, + B91448D531463AC31409FBDE /* Pods-Runner.profile-prod.xcconfig */, + 9F07595217A5DEEA0729C7FE /* Pods-Runner.release-prod.xcconfig */, + 072872AC24251C3536B9BABF /* Pods-Runner.debug-dev.xcconfig */, + 3A57DC804B7F6C11D18054D4 /* Pods-Runner.profile-dev.xcconfig */, + 18FFC3626FAEB6C0E2F8B8AC /* Pods-Runner.release-dev.xcconfig */, ); path = Pods; sourceTree = ""; @@ -212,7 +212,7 @@ isa = PBXNativeTarget; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildPhases = ( - F9F8C4175EB80A90DC64548E /* [CP] Check Pods Manifest.lock */, + 850DCFF539DDE60719A1CB47 /* [CP] Check Pods Manifest.lock */, 9740EEB61CF901F6004384FC /* Run Script */, 426B89AB2C46885100E24442 /* Copy Google Plist file */, 97C146EA1CF9000F007C117D /* Sources */, @@ -221,8 +221,8 @@ 42127D8A2C2839B60005AB40 /* Embed Foundation Extensions */, 9705A1C41CF9048500538489 /* Embed Frameworks */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - 2F67A041E3B0519B462D484D /* [CP] Embed Pods Frameworks */, - 1DD18D9D2FBAA8A200EFCE7E /* [CP] Copy Pods Resources */, + 1696D7B5D702A72B207AC179 /* [CP] Embed Pods Frameworks */, + C78E0E14E2A1712A91339475 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -294,24 +294,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1DD18D9D2FBAA8A200EFCE7E /* [CP] Copy Pods Resources */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Copy Pods Resources"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; - showEnvVarsInLog = 0; - }; - 2F67A041E3B0519B462D484D /* [CP] Embed Pods Frameworks */ = { + 1696D7B5D702A72B207AC179 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -362,6 +345,28 @@ shellPath = /bin/sh; shellScript = "# Type a script or drag a sc# Type a script or drag a script file from your workspace to insert its path.\nDEV_GOOGLE_PLIST=\"${PROJECT_DIR}/Config/Dev\"\nPROD_GOOGLE_PLIST=\"${PROJECT_DIR}/Config/Prod\"\n\necho \"build config is ${CONFIGURATION}\"\n\ncase \"${CONFIGURATION}\" in\n\n \"Debug-dev\" | \"AdHoc_Staging\" | \"Release-dev\" | \"Debug\")\n cp -r \"$DEV_GOOGLE_PLIST/GoogleService-Info.plist\" \"${PROJECT_DIR}/Runner/GoogleService-Info.plist\" ;;\n \"Debug-prod\" | \"Profile\" |\"Release-prod\" |\"Release\")\n cp -r \"$PROD_GOOGLE_PLIST/GoogleService-Info.plist\" \"${PROJECT_DIR}/Runner/GoogleService-Info.plist\" ;;\n\n *)\n ;;\nesac\n"; }; + 850DCFF539DDE60719A1CB47 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; alwaysOutOfDate = 1; @@ -377,26 +382,21 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build\n"; }; - F9F8C4175EB80A90DC64548E /* [CP] Check Pods Manifest.lock */ = { + C78E0E14E2A1712A91339475 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Copy Pods Resources"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-Runner-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -442,7 +442,7 @@ /* Begin XCBuildConfiguration section */ 0CE6142D2C21F36000559F1E /* Debug-prod */ = { isa = XCBuildConfiguration; - baseConfigurationReference = D03DCC70D4791528CB0929E7 /* Pods-Runner.debug-prod.xcconfig */; + baseConfigurationReference = 6F1A7E959CF9BBEC39BA4471 /* Pods-Runner.debug-prod.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; @@ -459,7 +459,7 @@ }; 0CE6142E2C21F36000559F1E /* Profile-prod */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 79A3E5C306D624AE31145607 /* Pods-Runner.profile-prod.xcconfig */; + baseConfigurationReference = B91448D531463AC31409FBDE /* Pods-Runner.profile-prod.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; @@ -476,7 +476,7 @@ }; 0CE6142F2C21F36000559F1E /* Release-prod */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 3724F354CEEDF26CAA89DE63 /* Pods-Runner.release-prod.xcconfig */; + baseConfigurationReference = 9F07595217A5DEEA0729C7FE /* Pods-Runner.release-prod.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; @@ -493,7 +493,7 @@ }; 0CE614302C21F36000559F1E /* Debug-dev */ = { isa = XCBuildConfiguration; - baseConfigurationReference = E4D40465AE1C862B18960D63 /* Pods-Runner.debug-dev.xcconfig */; + baseConfigurationReference = 072872AC24251C3536B9BABF /* Pods-Runner.debug-dev.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; @@ -510,7 +510,7 @@ }; 0CE614312C21F36000559F1E /* Profile-dev */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 92800DE2DBE33C9182F3F582 /* Pods-Runner.profile-dev.xcconfig */; + baseConfigurationReference = 3A57DC804B7F6C11D18054D4 /* Pods-Runner.profile-dev.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; @@ -527,7 +527,7 @@ }; 0CE614322C21F36000559F1E /* Release-dev */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 9E42219331AC03D460762ACB /* Pods-Runner.release-dev.xcconfig */; + baseConfigurationReference = 18FFC3626FAEB6C0E2F8B8AC /* Pods-Runner.release-dev.xcconfig */; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; @@ -546,7 +546,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -644,7 +644,7 @@ baseConfigurationReference = 08E3947A4217EF205E22BD44 /* prodDebug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; ASSETCATALOG_COMPILER_APPICON_NAME = "$(ASSET_PREFIX)AppIcon"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; @@ -719,7 +719,7 @@ baseConfigurationReference = 35656BCB5CBAA7C0BB162EE0 /* prodRelease.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; ASSETCATALOG_COMPILER_APPICON_NAME = "$(ASSET_PREFIX)AppIcon"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; @@ -789,7 +789,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -846,7 +846,7 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; @@ -991,7 +991,7 @@ baseConfigurationReference = 79B00761CB247C7EC7C8983B /* devRelease.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; ASSETCATALOG_COMPILER_APPICON_NAME = "$(ASSET_PREFIX)AppIcon"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1062,7 +1062,7 @@ baseConfigurationReference = 556416C8748DD3DD2C06A9DB /* devProfile.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; ASSETCATALOG_COMPILER_APPICON_NAME = "$(ASSET_PREFIX)AppIcon"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1132,7 +1132,7 @@ baseConfigurationReference = B52E83A1CC630E163A04DC50 /* prodProfile.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; ASSETCATALOG_COMPILER_APPICON_NAME = "$(ASSET_PREFIX)AppIcon"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; @@ -1202,7 +1202,7 @@ baseConfigurationReference = 17DD34CA2CFE6F3845E13C99 /* devDebug.xcconfig */; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; - ARCHS = $ARCHS_STANDARD_64_BIT; + ARCHS = "$ARCHS_STANDARD_64_BIT"; ASSETCATALOG_COMPILER_APPICON_NAME = "$(ASSET_PREFIX)AppIcon"; BUILD_LIBRARY_FOR_DISTRIBUTION = NO; CLANG_ANALYZER_NONNULL = YES; diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 98bcbf023..05c07c304 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -33,12 +33,12 @@ dependencies: shimmer: ^3.0.0 # Firebase - firebase_core: 3.3.0 - firebase_auth: 5.1.4 - firebase_messaging: 15.0.4 + firebase_core: 3.13.0 + firebase_auth: 5.5.3 + firebase_messaging: 15.2.5 # Analytics and Support - intercom_flutter: + intercom_flutter: 9.2.10 mixpanel_flutter: ^2.2.0 posthog_flutter: ^4.10.2 @@ -50,7 +50,7 @@ dependencies: pdf: ^3.11.0 intl: ^0.19.0 permission_handler: ^11.3.1 - share_plus: ^9.0.0 + share_plus: 10.0.1 shared_preferences: ^2.2.3 url_launcher: ^6.3.0 wav: ^1.3.0 @@ -94,7 +94,7 @@ dependencies: just_audio: ^0.9.39 frame_sdk: ^0.0.7 web_socket_channel: ^3.0.1 - talker_flutter: + talker_flutter: 4.5.0 flutter_silero_vad: git: url: https://github.com/char5742/flutter_silero_vad.git @@ -102,7 +102,7 @@ dependencies: timeago: ^3.7.0 app_links: ^6.3.2 flutter_svg: ^2.0.16 - file_picker: 8.0.7 + file_picker: 10.1.9 photo_view: ^0.15.0 font_awesome_flutter: ^10.8.0 From 306c0287cc5b5bc8d361bf5d55b499a5d4cc9a6d Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Fri, 16 May 2025 12:08:04 -0700 Subject: [PATCH 068/213] fetch chat messages if empty --- app/lib/pages/chat/page.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/lib/pages/chat/page.dart b/app/lib/pages/chat/page.dart index 8a6c42bc7..2e3acbd54 100644 --- a/app/lib/pages/chat/page.dart +++ b/app/lib/pages/chat/page.dart @@ -84,6 +84,10 @@ class ChatPageState extends State with AutomaticKeepAliveClientMixin { } }); SchedulerBinding.instance.addPostFrameCallback((_) async { + var provider = context.read(); + if (provider.messages.isEmpty) { + provider.refreshMessages(); + } scrollToBottom(); }); super.initState(); From 7eb3670b66364fd46d86ade96b25625310b8f158 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Fri, 16 May 2025 15:25:48 -0700 Subject: [PATCH 069/213] delete llm.py file --- backend/utils/llm.py | 155 ------------------------------------------- 1 file changed, 155 deletions(-) delete mode 100644 backend/utils/llm.py diff --git a/backend/utils/llm.py b/backend/utils/llm.py deleted file mode 100644 index 4f1d936fb..000000000 --- a/backend/utils/llm.py +++ /dev/null @@ -1,155 +0,0 @@ -import json -import re -import os -from datetime import datetime, timezone -from typing import List, Optional, Tuple - -import tiktoken -from langchain.schema import ( - HumanMessage, - SystemMessage, - AIMessage, -) -from langchain_core.output_parsers import PydanticOutputParser -from langchain_core.prompts import ChatPromptTemplate -from langchain_openai import ChatOpenAI, OpenAIEmbeddings -from pydantic import BaseModel, Field, ValidationError - -from database.redis_db import add_filter_category_item -from models.app import App -from models.chat import Message, MessageSender -from models.memories import Memory, MemoryCategory -from models.conversation import Structured, ConversationPhoto, CategoryEnum, Conversation, ActionItem, Event -from models.transcript_segment import TranscriptSegment -from models.trend import TrendEnum, ceo_options, company_options, software_product_options, hardware_product_options, \ - ai_product_options, TrendType -from utils.prompts import extract_memories_prompt, extract_learnings_prompt, extract_memories_text_content_prompt -from utils.llms.memory import get_prompt_memories - -llm_mini = ChatOpenAI(model='gpt-4o-mini') -llm_mini_stream = ChatOpenAI(model='gpt-4o-mini', streaming=True) -llm_large = ChatOpenAI(model='o1-preview') -llm_large_stream = ChatOpenAI(model='o1-preview', streaming=True, temperature=1) -llm_medium = ChatOpenAI(model='gpt-4o') -llm_medium_experiment = ChatOpenAI(model='gpt-4.1') -llm_medium_stream = ChatOpenAI(model='gpt-4o', streaming=True) -llm_persona_mini_stream = ChatOpenAI( - temperature=0.8, - model="google/gemini-flash-1.5-8b", - api_key=os.environ.get('OPENROUTER_API_KEY'), - base_url="https://openrouter.ai/api/v1", - default_headers={"X-Title": "Omi Chat"}, - streaming=True, -) -llm_persona_medium_stream = ChatOpenAI( - temperature=0.8, - model="anthropic/claude-3.5-sonnet", - api_key=os.environ.get('OPENROUTER_API_KEY'), - base_url="https://openrouter.ai/api/v1", - default_headers={"X-Title": "Omi Chat"}, - streaming=True, -) -embeddings = OpenAIEmbeddings(model="text-embedding-3-large") -parser = PydanticOutputParser(pydantic_object=Structured) - -encoding = tiktoken.encoding_for_model('gpt-4') - - -def num_tokens_from_string(string: str) -> int: - """Returns the number of tokens in a text string.""" - num_tokens = len(encoding.encode(string)) - return num_tokens - - -# TODO: include caching layer, redis - - -# ********************************************** -# ********** CONVERSATION PROCESSING *********** -# ********************************************** -# move to utils/llm/conversation_processing.py - - -# ************************************** -# ************* OPENGLASS ************** -# ************************************** - -# move to utils/llm/openglass.py - - -# ************************************************** -# ************* EXTERNAL INTEGRATIONS ************** -# ************************************************** -# move to utils/llm/external_integrations.py - - -# **************************************** -# ************* CHAT BASICS ************** -# **************************************** - - -# ********************************************* -# ************* RETRIEVAL + CHAT ************** -# ********************************************* - - -# ************************************************** -# ************* RETRIEVAL (EMOTIONAL) ************** -# ************************************************** - -# moved to utils/llm/chat.py - - -# ********************************************* -# ************* MEMORIES (FACTS) ************** -# ********************************************* - - -# ********************************** -# ************* TRENDS ************** -# ********************************** -# moved to utils/llm/trends.py - - -# ********************************************************** -# ************* RANDOM JOAN SPECIFIC FEATURES ************** -# ********************************************************** -# moved to utils/llm/followup.py - - -# ********************************************** -# ************* CHAT V2 LANGGRAPH ************** -# ********************************************** -# moved to utils/llm/chat.py - - -# ************************************************** -# ************* REALTIME V2 LANGGRAPH ************** -# ************************************************** -# moved to utils/llm/chat.py - - -# ************************************************** -# ************* PROACTIVE NOTIFICATION ************* -# ************************************************** -# moved to utils/llm/proactive_notification.py - - -# ************************************************** -# *************** APPS AI GENERATE ***************** -# ************************************************** - - -# ************************************************** -# ******************* PERSONA ********************** -# ************************************************** -# moved to llm/persona.py - - -# ************************************************** -# ***************** FACT/MEMORY ******************** -# ************************************************** -# moved to llm/memories.py - - - From 9314d7167c0363c5e21df3520bdb16fbdefdf1e4 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Fri, 16 May 2025 16:14:54 -0700 Subject: [PATCH 070/213] make memories private by default --- backend/models/memories.py | 2 +- backend/utils/conversations/process_conversation.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/models/memories.py b/backend/models/memories.py index ff7cb6574..d4e74e98d 100644 --- a/backend/models/memories.py +++ b/backend/models/memories.py @@ -35,7 +35,7 @@ class MemoryCategory(str, Enum): class Memory(BaseModel): content: str = Field(description="The content of the memory") category: MemoryCategory = Field(description="The category of the memory", default=MemoryCategory.other) - visibility: str = Field(description="The visibility of the memory", default='public') + visibility: str = Field(description="The visibility of the memory", default='private') tags: List[str] = Field(description="The tags of the memory and learning", default=[]) @staticmethod diff --git a/backend/utils/conversations/process_conversation.py b/backend/utils/conversations/process_conversation.py index bddad7bc3..9edade5b0 100644 --- a/backend/utils/conversations/process_conversation.py +++ b/backend/utils/conversations/process_conversation.py @@ -202,9 +202,9 @@ def _extract_memories(uid: str, conversation: Conversation): new_memories = new_memories_extractor(uid, conversation.transcript_segments) parsed_memories = [] - for fact in new_memories: - parsed_memories.append(MemoryDB.from_memory(fact, uid, conversation.id, False)) - print('_extract_memories:', fact.category.value.upper(), '|', fact.content) + for memory in new_memories: + parsed_memories.append(MemoryDB.from_memory(memory, uid, conversation.id, False)) + print('_extract_memories:', memory.category.value.upper(), '|', memory.content) if len(parsed_memories) == 0: print(f"No memories extracted for conversation {conversation.id}") From cfc5f824dca18c41641639a8e40f9abc9310f3c2 Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Fri, 16 May 2025 19:14:45 -0700 Subject: [PATCH 071/213] add cache control header to apps logo and thumbnails --- backend/utils/other/storage.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/backend/utils/other/storage.py b/backend/utils/other/storage.py index 766e77b69..c046ca5d0 100644 --- a/backend/utils/other/storage.py +++ b/backend/utils/other/storage.py @@ -243,6 +243,7 @@ def upload_plugin_logo(file_path: str, plugin_id: str): bucket = storage_client.bucket(omi_plugins_bucket) path = f'{plugin_id}.png' blob = bucket.blob(path) + blob.cache_control = 'public, no-cache' blob.upload_from_filename(file_path) return f'https://storage.googleapis.com/{omi_plugins_bucket}/{path}' @@ -258,8 +259,10 @@ def upload_app_thumbnail(file_path: str, thumbnail_id: str) -> str: bucket = storage_client.bucket(app_thumbnails_bucket) path = f'{thumbnail_id}.jpg' blob = bucket.blob(path) + blob.cache_control = 'public, no-cache' blob.upload_from_filename(file_path) - return f'https://storage.googleapis.com/{app_thumbnails_bucket}/{path}' + public_url = f'https://storage.googleapis.com/{app_thumbnails_bucket}/{path}' + return public_url def get_app_thumbnail_url(thumbnail_id: str) -> str: path = f'{thumbnail_id}.jpg' From da6d28ae9d8eeb25415bc25e24658eb3ac0adf2e Mon Sep 17 00:00:00 2001 From: Mohammed Mohsin <59914433+mdmohsin7@users.noreply.github.com> Date: Fri, 16 May 2025 19:17:02 -0700 Subject: [PATCH 072/213] bump cached_network_image and evict cached image on update --- app/lib/pages/apps/providers/add_app_provider.dart | 4 ++++ app/lib/providers/app_provider.dart | 2 +- app/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/lib/pages/apps/providers/add_app_provider.dart b/app/lib/pages/apps/providers/add_app_provider.dart index 87f8809b9..d2c8a687f 100644 --- a/app/lib/pages/apps/providers/add_app_provider.dart +++ b/app/lib/pages/apps/providers/add_app_provider.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; @@ -663,6 +664,9 @@ class AddAppProvider extends ChangeNotifier { var file = await imagePicker.pickImage(source: ImageSource.gallery); if (file != null) { imageFile = File(file.path); + if (imageUrl != null) { + await CachedNetworkImage.evictFromCache(imageUrl!, cacheKey: imageUrl); + } imageUrl = null; } notifyListeners(); diff --git a/app/lib/providers/app_provider.dart b/app/lib/providers/app_provider.dart index 6164bef0e..8b93fdd9e 100644 --- a/app/lib/providers/app_provider.dart +++ b/app/lib/providers/app_provider.dart @@ -56,7 +56,7 @@ class AppProvider extends BaseProvider { var app = await getAppDetailsServer(id); if (app != null) { var oldApp = apps.where((element) => element.id == id).firstOrNull; - if (oldApp == null){ + if (oldApp == null) { return null; } var idx = apps.indexOf(oldApp); diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 05c07c304..3404f8a69 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -84,7 +84,7 @@ dependencies: sign_in_with_apple: ^6.1.1 google_sign_in: 6.2.1 location: ^7.0.0 - cached_network_image: ^3.3.1 + cached_network_image: 3.4.1 map_launcher: ^3.3.1 internet_connection_checker_plus: ^2.5.0 geolocator: From 0f3837a6ad9bda1d43629d095956600cfbdfbaa1 Mon Sep 17 00:00:00 2001 From: Thinh Date: Sat, 17 May 2025 12:17:23 +0700 Subject: [PATCH 073/213] The empty convos fixes (#2386) * Fallback to completed, processing statuses on getting convos with an empty statues param; Filter completed only(not processing or in_progress) convos on fetching new convos * Add support new processing convos --- app/lib/backend/http/api/users.dart | 1 - app/lib/pages/home/page.dart | 15 +++++------ app/lib/providers/conversation_provider.dart | 26 ++++++++++++++++---- backend/routers/conversations.py | 3 ++- 4 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/lib/backend/http/api/users.dart b/app/lib/backend/http/api/users.dart index e2591c229..cebd34a63 100644 --- a/app/lib/backend/http/api/users.dart +++ b/app/lib/backend/http/api/users.dart @@ -183,7 +183,6 @@ Future> getAllPeople({bool includeSpeechSamples = true}) async { body: '', ); if (response == null) return []; - debugPrint('getAllPeople response: ${response.body}'); if (response.statusCode == 200) { List peopleJson = jsonDecode(response.body); List people = peopleJson.mapIndexed((idx, json) { diff --git a/app/lib/pages/home/page.dart b/app/lib/pages/home/page.dart index 30d5f68a9..e98ae0578 100644 --- a/app/lib/pages/home/page.dart +++ b/app/lib/pages/home/page.dart @@ -2,30 +2,29 @@ import 'dart:async'; import 'dart:io'; import 'package:flutter/material.dart'; -import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:omi/gen/assets.gen.dart'; -import 'package:omi/pages/persona/persona_provider.dart'; +import 'package:gradient_borders/gradient_borders.dart'; +import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:omi/backend/http/api/users.dart'; import 'package:omi/backend/preferences.dart'; import 'package:omi/backend/schema/app.dart'; import 'package:omi/backend/schema/geolocation.dart'; +import 'package:omi/gen/assets.gen.dart'; import 'package:omi/main.dart'; import 'package:omi/pages/apps/page.dart'; import 'package:omi/pages/chat/page.dart'; import 'package:omi/pages/conversations/conversations_page.dart'; -import 'package:omi/pages/memories/page.dart'; import 'package:omi/pages/home/widgets/chat_apps_dropdown_widget.dart'; -import 'package:omi/pages/persona/persona_profile.dart'; -import 'package:omi/pages/home/widgets/speech_language_sheet.dart'; +import 'package:omi/pages/memories/page.dart'; import 'package:omi/pages/settings/page.dart'; import 'package:omi/providers/app_provider.dart'; import 'package:omi/providers/capture_provider.dart'; import 'package:omi/providers/connectivity_provider.dart'; +import 'package:omi/providers/conversation_provider.dart'; import 'package:omi/providers/device_provider.dart'; import 'package:omi/providers/home_provider.dart'; -import 'package:omi/providers/conversation_provider.dart'; import 'package:omi/providers/message_provider.dart'; import 'package:omi/services/notifications.dart'; import 'package:omi/utils/analytics/analytics_manager.dart'; @@ -33,8 +32,6 @@ import 'package:omi/utils/analytics/mixpanel.dart'; import 'package:omi/utils/audio/foreground.dart'; import 'package:omi/utils/other/temp.dart'; import 'package:omi/widgets/upgrade_alert.dart'; -import 'package:gradient_borders/gradient_borders.dart'; -import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:provider/provider.dart'; import 'package:upgrader/upgrader.dart'; diff --git a/app/lib/providers/conversation_provider.dart b/app/lib/providers/conversation_provider.dart index e4133de95..b07c63604 100644 --- a/app/lib/providers/conversation_provider.dart +++ b/app/lib/providers/conversation_provider.dart @@ -163,12 +163,26 @@ class ConversationProvider extends ChangeNotifier implements IWalServiceListener Future fetchNewConversations() async { List newConversations = await getConversationsFromServer(); - List upsertConvos = - newConversations.where((c) => conversations.indexWhere((cc) => cc.id == c.id) == -1).toList(); - if (upsertConvos.isEmpty) { - return; + List upsertConvos = []; + + // processing convos + upsertConvos = newConversations + .where((c) => + c.status == ConversationStatus.processing && + processingConversations.indexWhere((cc) => cc.id == c.id) == -1) + .toList(); + if (upsertConvos.isNotEmpty) { + processingConversations.insertAll(0, upsertConvos); } - conversations.insertAll(0, upsertConvos); + + // completed convos + upsertConvos = newConversations + .where((c) => c.status == ConversationStatus.completed && conversations.indexWhere((cc) => cc.id == c.id) == -1) + .toList(); + if (upsertConvos.isNotEmpty) { + conversations.insertAll(0, upsertConvos); + } + _groupConversationsByDateWithoutNotify(); notifyListeners(); } @@ -181,8 +195,10 @@ class ConversationProvider extends ChangeNotifier implements IWalServiceListener conversations = await getConversationsFromServer(); + // processing convos processingConversations = conversations.where((m) => m.status == ConversationStatus.processing).toList(); + // completed convos conversations = conversations.where((m) => m.status == ConversationStatus.completed).toList(); if (conversations.isEmpty) { conversations = SharedPreferencesUtil().cachedConversations; diff --git a/backend/routers/conversations.py b/backend/routers/conversations.py index 0d22b8d3c..82ff3ad21 100644 --- a/backend/routers/conversations.py +++ b/backend/routers/conversations.py @@ -76,7 +76,7 @@ def reprocess_conversation( @router.get('/v1/conversations', response_model=List[Conversation], tags=['conversations']) -def get_conversations(limit: int = 100, offset: int = 0, statuses: str = "", include_discarded: bool = True, +def get_conversations(limit: int = 100, offset: int = 0, statuses: str = "processing,completed", include_discarded: bool = True, uid: str = Depends(auth.get_current_user_uid)): print('get_conversations', uid, limit, offset, statuses) return conversations_db.get_conversations(uid, limit, offset, include_discarded=include_discarded, @@ -85,6 +85,7 @@ def get_conversations(limit: int = 100, offset: int = 0, statuses: str = "", inc @router.get("/v1/conversations/{conversation_id}", response_model=Conversation, tags=['conversations']) def get_conversation_by_id(conversation_id: str, uid: str = Depends(auth.get_current_user_uid)): + print('get_conversation_by_id', uid, conversation_id) return _get_conversation_by_id(uid, conversation_id) From a3eeae17b9e1ae3cd06a33c10c2d321a03797355 Mon Sep 17 00:00:00 2001 From: thainguyensunya <107201766+thainguyensunya@users.noreply.github.com> Date: Sat, 17 May 2025 14:45:59 +0700 Subject: [PATCH 074/213] Test/self hosted deepgram nova 3 multilingual (#2387) --- .../{ => nova-2}/.helmignore | 0 .../{ => nova-2}/CHANGELOG.md | 0 .../{ => nova-2}/Chart.yaml | 0 .../{ => nova-2}/README.md | 0 .../{ => nova-2}/README.md.gotmpl | 0 .../charts/cluster-autoscaler-9.46.0.tgz | Bin .../charts/gpu-operator-v24.9.2.tgz | Bin .../charts/kube-prometheus-stack-69.3.2.tgz | Bin .../charts/prometheus-adapter-4.11.0.tgz | Bin .../dev_omi_deepgram_grafana_alb_cert.yaml | 0 .../nova-2/dev_omi_values.yaml | 182 + .../prod_omi_deepgram_grafana_alb_cert.yaml | 0 .../{ => nova-2}/prod_omi_values.yaml | 8 +- .../01-basic-setup-aws.cluster-config.yaml | 0 .../samples/01-basic-setup-aws.values.yaml | 0 .../samples/02-basic-setup-gcp.yaml | 0 .../samples/03-basic-setup-onprem.yaml | 0 .../{ => nova-2}/samples/README.md | 0 .../{ => nova-2}/templates/NOTES.txt | 0 .../{ => nova-2}/templates/_helpers.tpl | 0 .../templates/api/api.config.yaml | 0 .../templates/api/api.deployment.yaml | 0 .../{ => nova-2}/templates/api/api.hpa.yaml | 0 .../templates/api/api.ingress.yaml | 0 .../{ => nova-2}/templates/api/api.rbac.yaml | 0 .../templates/api/api.service.yaml | 0 .../templates/engine/engine.config.yaml | 0 .../templates/engine/engine.deployment.yaml | 0 .../templates/engine/engine.hpa.yaml | 0 .../templates/engine/engine.rbac.yaml | 0 .../templates/engine/engine.service.yaml | 0 .../license-proxy/license-proxy.config.yaml | 0 .../license-proxy.deployment.yaml | 0 .../license-proxy/license-proxy.rbac.yaml | 0 .../license-proxy/license-proxy.service.yaml | 0 .../volumes/aws/efs-model-download.job.yaml | 0 .../templates/volumes/aws/efs.pv.yaml | 0 .../templates/volumes/aws/efs.pvc.yaml | 0 .../volumes/aws/efs.storageClass.yaml | 0 .../templates/volumes/gcp/gpd.pv.yaml | 0 .../templates/volumes/gcp/gpd.pvc.yaml | 0 .../{ => nova-2}/values.yaml | 0 .../deepgram-self-hosted/nova-3/.helmignore | 23 + .../deepgram-self-hosted/nova-3/CHANGELOG.md | 201 + .../deepgram-self-hosted/nova-3/Chart.yaml | 42 + .../deepgram-self-hosted/nova-3/README.md | 331 + .../nova-3/README.md.gotmpl | 168 + .../charts/cluster-autoscaler/.helmignore | 23 + .../charts/cluster-autoscaler/Chart.yaml | 13 + .../charts/cluster-autoscaler/README.md | 528 + .../cluster-autoscaler/README.md.gotmpl | 417 + .../cluster-autoscaler/templates/NOTES.txt | 18 + .../cluster-autoscaler/templates/_helpers.tpl | 160 + .../templates/clusterrole.yaml | 176 + .../templates/clusterrolebinding.yaml | 16 + .../templates/configmap.yaml | 416 + .../templates/deployment.yaml | 372 + .../templates/extra-manifests.yaml | 4 + .../cluster-autoscaler/templates/pdb.yaml | 16 + .../templates/podsecuritypolicy.yaml | 42 + .../priority-expander-configmap.yaml | 25 + .../templates/prometheusrule.yaml | 15 + .../cluster-autoscaler/templates/role.yaml | 87 + .../templates/rolebinding.yaml | 17 + .../cluster-autoscaler/templates/secret.yaml | 32 + .../cluster-autoscaler/templates/service.yaml | 39 + .../templates/serviceaccount.yaml | 13 + .../templates/servicemonitor.yaml | 36 + .../cluster-autoscaler/templates/vpa.yaml | 20 + .../charts/cluster-autoscaler/values.yaml | 470 + .../nova-3/charts/gpu-operator/.helmignore | 22 + .../nova-3/charts/gpu-operator/Chart.yaml | 23 + .../charts/node-feature-discovery/.helmignore | 23 + .../charts/node-feature-discovery/Chart.yaml | 14 + .../charts/node-feature-discovery/README.md | 10 + .../crds/nfd-api-crds.yaml | 710 + .../templates/_helpers.tpl | 107 + .../templates/cert-manager-certs.yaml | 80 + .../templates/cert-manager-issuer.yaml | 42 + .../templates/clusterrole.yaml | 133 + .../templates/clusterrolebinding.yaml | 52 + .../templates/master.yaml | 152 + .../templates/nfd-gc.yaml | 85 + .../templates/nfd-master-conf.yaml | 12 + .../templates/nfd-topologyupdater-conf.yaml | 12 + .../templates/nfd-worker-conf.yaml | 12 + .../templates/post-delete-job.yaml | 94 + .../templates/prometheus.yaml | 26 + .../templates/role.yaml | 24 + .../templates/rolebinding.yaml | 18 + .../templates/service.yaml | 20 + .../templates/serviceaccount.yaml | 58 + .../templates/topologyupdater-crds.yaml | 278 + .../templates/topologyupdater.yaml | 171 + .../templates/worker.yaml | 186 + .../charts/node-feature-discovery/values.yaml | 593 + .../crds/nvidia.com_clusterpolicies.yaml | 2384 ++++ .../crds/nvidia.com_nvidiadrivers.yaml | 797 ++ .../gpu-operator/templates/_helpers.tpl | 80 + .../gpu-operator/templates/cleanup_crd.yaml | 45 + .../gpu-operator/templates/clusterpolicy.yaml | 683 + .../gpu-operator/templates/clusterrole.yaml | 146 + .../templates/clusterrolebinding.yaml | 18 + .../templates/dcgm_exporter_config.yaml | 14 + .../gpu-operator/templates/mig_config.yaml | 10 + .../templates/nodefeaturerules.yaml | 107 + .../gpu-operator/templates/nvidiadriver.yaml | 119 + .../gpu-operator/templates/operator.yaml | 99 + .../gpu-operator/templates/plugin_config.yaml | 11 + .../templates/readonlyfs_scc.openshift.yaml | 49 + .../charts/gpu-operator/templates/role.yaml | 84 + .../gpu-operator/templates/rolebinding.yaml | 15 + .../templates/serviceaccount.yaml | 7 + .../gpu-operator/templates/upgrade_crd.yaml | 95 + .../nova-3/charts/gpu-operator/values.yaml | 602 + .../kube-prometheus-stack/.editorconfig | 5 + .../charts/kube-prometheus-stack/.helmignore | 29 + .../kube-prometheus-stack/CONTRIBUTING.md | 12 + .../charts/kube-prometheus-stack/Chart.yaml | 65 + .../charts/kube-prometheus-stack/README.md | 1090 ++ .../charts/crds/Chart.yaml | 3 + .../charts/crds/README.md | 3 + .../crds/crds/crd-alertmanagerconfigs.yaml | 5866 ++++++++ .../charts/crds/crds/crd-alertmanagers.yaml | 7839 +++++++++++ .../charts/crds/crds/crd-podmonitors.yaml | 905 ++ .../charts/crds/crds/crd-probes.yaml | 881 ++ .../crds/crds/crd-prometheusagents.yaml | 9525 +++++++++++++ .../charts/crds/crds/crd-prometheuses.yaml | 11322 ++++++++++++++++ .../charts/crds/crds/crd-prometheusrules.yaml | 140 + .../charts/crds/crds/crd-scrapeconfigs.yaml | 4832 +++++++ .../charts/crds/crds/crd-servicemonitors.yaml | 929 ++ .../charts/crds/crds/crd-thanosrulers.yaml | 7523 ++++++++++ .../charts/grafana/.helmignore | 23 + .../charts/grafana/Chart.yaml | 35 + .../charts/grafana/README.md | 777 ++ .../charts/grafana/ci/default-values.yaml | 1 + .../grafana/ci/with-affinity-values.yaml | 16 + .../ci/with-dashboard-json-values.yaml | 53 + .../grafana/ci/with-dashboard-values.yaml | 19 + .../ci/with-extraconfigmapmounts-values.yaml | 7 + .../ci/with-image-renderer-values.yaml | 19 + .../charts/grafana/ci/with-persistence.yaml | 3 + .../grafana/dashboards/custom-dashboard.json | 1 + .../charts/grafana/templates/NOTES.txt | 55 + .../charts/grafana/templates/_config.tpl | 172 + .../charts/grafana/templates/_helpers.tpl | 276 + .../charts/grafana/templates/_pod.tpl | 1296 ++ .../charts/grafana/templates/clusterrole.yaml | 25 + .../grafana/templates/clusterrolebinding.yaml | 24 + .../grafana/templates/configSecret.yaml | 43 + .../configmap-dashboard-provider.yaml | 15 + .../charts/grafana/templates/configmap.yaml | 20 + .../templates/dashboards-json-configmap.yaml | 38 + .../charts/grafana/templates/deployment.yaml | 53 + .../grafana/templates/extra-manifests.yaml | 4 + .../grafana/templates/headless-service.yaml | 22 + .../charts/grafana/templates/hpa.yaml | 52 + .../templates/image-renderer-deployment.yaml | 131 + .../grafana/templates/image-renderer-hpa.yaml | 47 + .../image-renderer-network-policy.yaml | 79 + .../templates/image-renderer-service.yaml | 31 + .../image-renderer-servicemonitor.yaml | 48 + .../charts/grafana/templates/ingress.yaml | 78 + .../grafana/templates/networkpolicy.yaml | 61 + .../templates/poddisruptionbudget.yaml | 22 + .../grafana/templates/podsecuritypolicy.yaml | 49 + .../charts/grafana/templates/pvc.yaml | 39 + .../charts/grafana/templates/role.yaml | 32 + .../charts/grafana/templates/rolebinding.yaml | 25 + .../charts/grafana/templates/secret-env.yaml | 14 + .../charts/grafana/templates/secret.yaml | 16 + .../charts/grafana/templates/service.yaml | 67 + .../grafana/templates/serviceaccount.yaml | 17 + .../grafana/templates/servicemonitor.yaml | 52 + .../charts/grafana/templates/statefulset.yaml | 56 + .../templates/tests/test-configmap.yaml | 20 + .../tests/test-podsecuritypolicy.yaml | 32 + .../grafana/templates/tests/test-role.yaml | 17 + .../templates/tests/test-rolebinding.yaml | 20 + .../templates/tests/test-serviceaccount.yaml | 12 + .../charts/grafana/templates/tests/test.yaml | 53 + .../charts/grafana/values.yaml | 1339 ++ .../charts/kube-state-metrics/.helmignore | 21 + .../charts/kube-state-metrics/Chart.yaml | 26 + .../charts/kube-state-metrics/README.md | 85 + .../kube-state-metrics/templates/NOTES.txt | 23 + .../kube-state-metrics/templates/_helpers.tpl | 156 + .../templates/ciliumnetworkpolicy.yaml | 33 + .../templates/clusterrolebinding.yaml | 20 + .../templates/crs-configmap.yaml | 16 + .../templates/deployment.yaml | 312 + .../templates/extra-manifests.yaml | 4 + .../templates/kubeconfig-secret.yaml | 12 + .../templates/networkpolicy.yaml | 43 + .../kube-state-metrics/templates/pdb.yaml | 18 + .../templates/podsecuritypolicy.yaml | 39 + .../templates/psp-clusterrole.yaml | 19 + .../templates/psp-clusterrolebinding.yaml | 16 + .../templates/rbac-configmap.yaml | 22 + .../kube-state-metrics/templates/role.yaml | 212 + .../templates/rolebinding.yaml | 24 + .../kube-state-metrics/templates/service.yaml | 53 + .../templates/serviceaccount.yaml | 17 + .../templates/servicemonitor.yaml | 120 + .../templates/stsdiscovery-role.yaml | 26 + .../templates/stsdiscovery-rolebinding.yaml | 17 + .../templates/verticalpodautoscaler.yaml | 44 + .../charts/kube-state-metrics/values.yaml | 517 + .../prometheus-node-exporter/.helmignore | 21 + .../prometheus-node-exporter/Chart.yaml | 25 + .../charts/prometheus-node-exporter/README.md | 96 + .../ci/port-values.yaml | 3 + .../templates/NOTES.txt | 29 + .../templates/_helpers.tpl | 202 + .../templates/clusterrole.yaml | 19 + .../templates/clusterrolebinding.yaml | 20 + .../templates/daemonset.yaml | 311 + .../templates/endpoints.yaml | 18 + .../templates/extra-manifests.yaml | 4 + .../templates/networkpolicy.yaml | 23 + .../templates/podmonitor.yaml | 91 + .../templates/psp-clusterrole.yaml | 14 + .../templates/psp-clusterrolebinding.yaml | 16 + .../templates/psp.yaml | 49 + .../templates/rbac-configmap.yaml | 16 + .../templates/service.yaml | 35 + .../templates/serviceaccount.yaml | 17 + .../templates/servicemonitor.yaml | 61 + .../templates/verticalpodautoscaler.yaml | 40 + .../prometheus-node-exporter/values.yaml | 533 + .../prometheus-windows-exporter/.helmignore | 21 + .../prometheus-windows-exporter/Chart.yaml | 17 + .../prometheus-windows-exporter/README.md | 42 + .../templates/_helpers.tpl | 185 + .../templates/config.yaml | 14 + .../templates/daemonset.yaml | 192 + .../templates/podmonitor.yaml | 91 + .../templates/service.yaml | 32 + .../templates/serviceaccount.yaml | 17 + .../templates/servicemonitor.yaml | 61 + .../prometheus-windows-exporter/values.yaml | 369 + .../kube-prometheus-stack/templates/NOTES.txt | 4 + .../templates/_helpers.tpl | 320 + .../templates/alertmanager/alertmanager.yaml | 193 + .../templates/alertmanager/extrasecret.yaml | 20 + .../templates/alertmanager/ingress.yaml | 78 + .../alertmanager/ingressperreplica.yaml | 67 + .../alertmanager/podDisruptionBudget.yaml | 21 + .../templates/alertmanager/psp-role.yaml | 23 + .../alertmanager/psp-rolebinding.yaml | 20 + .../templates/alertmanager/psp.yaml | 47 + .../templates/alertmanager/secret.yaml | 29 + .../templates/alertmanager/service.yaml | 72 + .../alertmanager/serviceaccount.yaml | 21 + .../alertmanager/servicemonitor.yaml | 93 + .../alertmanager/serviceperreplica.yaml | 49 + .../templates/exporters/core-dns/service.yaml | 28 + .../exporters/core-dns/servicemonitor.yaml | 48 + .../kube-api-server/servicemonitor.yaml | 47 + .../kube-controller-manager/endpoints.yaml | 22 + .../kube-controller-manager/service.yaml | 33 + .../servicemonitor.yaml | 59 + .../templates/exporters/kube-dns/service.yaml | 32 + .../exporters/kube-dns/servicemonitor.yaml | 61 + .../exporters/kube-etcd/endpoints.yaml | 20 + .../exporters/kube-etcd/service.yaml | 31 + .../exporters/kube-etcd/servicemonitor.yaml | 65 + .../exporters/kube-proxy/endpoints.yaml | 20 + .../exporters/kube-proxy/service.yaml | 31 + .../exporters/kube-proxy/servicemonitor.yaml | 53 + .../exporters/kube-scheduler/endpoints.yaml | 22 + .../exporters/kube-scheduler/service.yaml | 33 + .../kube-scheduler/servicemonitor.yaml | 59 + .../exporters/kubelet/servicemonitor.yaml | 233 + .../templates/extra-objects.yaml | 4 + .../grafana/configmap-dashboards.yaml | 24 + .../grafana/configmaps-datasources.yaml | 81 + .../alertmanager-overview.yaml | 24 + .../grafana/dashboards-1.14/apiserver.yaml | 24 + .../dashboards-1.14/cluster-total.yaml | 24 + .../dashboards-1.14/controller-manager.yaml | 24 + .../grafana/dashboards-1.14/etcd.yaml | 24 + .../dashboards-1.14/grafana-overview.yaml | 24 + .../grafana/dashboards-1.14/k8s-coredns.yaml | 24 + .../k8s-resources-cluster.yaml | 24 + .../k8s-resources-multicluster.yaml | 24 + .../k8s-resources-namespace.yaml | 24 + .../dashboards-1.14/k8s-resources-node.yaml | 24 + .../dashboards-1.14/k8s-resources-pod.yaml | 24 + .../k8s-resources-windows-cluster.yaml | 24 + .../k8s-resources-windows-namespace.yaml | 24 + .../k8s-resources-windows-pod.yaml | 24 + .../k8s-resources-workload.yaml | 24 + .../k8s-resources-workloads-namespace.yaml | 24 + .../k8s-windows-cluster-rsrc-use.yaml | 24 + .../k8s-windows-node-rsrc-use.yaml | 24 + .../grafana/dashboards-1.14/kubelet.yaml | 24 + .../dashboards-1.14/namespace-by-pod.yaml | 24 + .../namespace-by-workload.yaml | 24 + .../node-cluster-rsrc-use.yaml | 24 + .../dashboards-1.14/node-rsrc-use.yaml | 24 + .../grafana/dashboards-1.14/nodes-darwin.yaml | 24 + .../grafana/dashboards-1.14/nodes.yaml | 24 + .../persistentvolumesusage.yaml | 24 + .../grafana/dashboards-1.14/pod-total.yaml | 24 + .../prometheus-remote-write.yaml | 24 + .../grafana/dashboards-1.14/prometheus.yaml | 24 + .../grafana/dashboards-1.14/proxy.yaml | 24 + .../grafana/dashboards-1.14/scheduler.yaml | 24 + .../dashboards-1.14/workload-total.yaml | 24 + .../_prometheus-operator.tpl | 7 + .../_prometheus-operator-webhook.tpl | 6 + .../deployment/deployment.yaml | 143 + .../admission-webhooks/deployment/pdb.yaml | 15 + .../deployment/service.yaml | 62 + .../deployment/serviceaccount.yaml | 15 + .../ciliumnetworkpolicy-createSecret.yaml | 36 + .../ciliumnetworkpolicy-patchWebhook.yaml | 36 + .../job-patch/clusterrole.yaml | 33 + .../job-patch/clusterrolebinding.yaml | 20 + .../job-patch/job-createSecret.yaml | 70 + .../job-patch/job-patchWebhook.yaml | 71 + .../job-patch/networkpolicy-createSecret.yaml | 33 + .../job-patch/networkpolicy-patchWebhook.yaml | 33 + .../admission-webhooks/job-patch/psp.yaml | 47 + .../admission-webhooks/job-patch/role.yaml | 21 + .../job-patch/rolebinding.yaml | 21 + .../job-patch/serviceaccount.yaml | 18 + .../mutatingWebhookConfiguration.yaml | 81 + .../validatingWebhookConfiguration.yaml | 81 + .../aggregate-clusterroles.yaml | 29 + .../prometheus-operator/certmanager.yaml | 55 + .../ciliumnetworkpolicy.yaml | 40 + .../prometheus-operator/clusterrole.yaml | 109 + .../clusterrolebinding.yaml | 16 + .../prometheus-operator/deployment.yaml | 206 + .../prometheus-operator/networkpolicy.yaml | 29 + .../prometheus-operator/psp-clusterrole.yaml | 21 + .../psp-clusterrolebinding.yaml | 18 + .../templates/prometheus-operator/psp.yaml | 46 + .../prometheus-operator/service.yaml | 61 + .../prometheus-operator/serviceaccount.yaml | 14 + .../prometheus-operator/servicemonitor.yaml | 47 + .../verticalpodautoscaler.yaml | 40 + .../templates/prometheus/_rules.tpl | 44 + .../additionalAlertRelabelConfigs.yaml | 16 + .../additionalAlertmanagerConfigs.yaml | 16 + .../prometheus/additionalPrometheusRules.yaml | 43 + .../prometheus/additionalScrapeConfigs.yaml | 20 + .../prometheus/ciliumnetworkpolicy.yaml | 27 + .../templates/prometheus/clusterrole.yaml | 37 + .../prometheus/clusterrolebinding.yaml | 18 + .../templates/prometheus/csi-secret.yaml | 12 + .../templates/prometheus/extrasecret.yaml | 20 + .../templates/prometheus/ingress.yaml | 77 + .../prometheus/ingressThanosSidecar.yaml | 77 + .../prometheus/ingressperreplica.yaml | 67 + .../templates/prometheus/networkpolicy.yaml | 34 + .../prometheus/podDisruptionBudget.yaml | 25 + .../templates/prometheus/podmonitors.yaml | 38 + .../templates/prometheus/prometheus.yaml | 475 + .../templates/prometheus/psp-clusterrole.yaml | 22 + .../prometheus/psp-clusterrolebinding.yaml | 19 + .../templates/prometheus/psp.yaml | 58 + .../rules-1.14/alertmanager.rules.yaml | 303 + .../rules-1.14/config-reloaders.yaml | 57 + .../templates/prometheus/rules-1.14/etcd.yaml | 459 + .../prometheus/rules-1.14/general.rules.yaml | 125 + ...les.container_cpu_usage_seconds_total.yaml | 43 + .../k8s.rules.container_memory_cache.yaml | 42 + .../k8s.rules.container_memory_rss.yaml | 42 + .../k8s.rules.container_memory_swap.yaml | 42 + ...es.container_memory_working_set_bytes.yaml | 42 + .../k8s.rules.container_resource.yaml | 168 + .../rules-1.14/k8s.rules.pod_owner.yaml | 107 + .../kube-apiserver-availability.rules.yaml | 273 + .../kube-apiserver-burnrate.rules.yaml | 440 + .../kube-apiserver-histogram.rules.yaml | 53 + .../rules-1.14/kube-apiserver-slos.yaml | 159 + .../kube-prometheus-general.rules.yaml | 49 + .../kube-prometheus-node-recording.rules.yaml | 93 + .../rules-1.14/kube-scheduler.rules.yaml | 135 + .../rules-1.14/kube-state-metrics.yaml | 152 + .../prometheus/rules-1.14/kubelet.rules.yaml | 63 + .../rules-1.14/kubernetes-apps.yaml | 568 + .../rules-1.14/kubernetes-resources.yaml | 282 + .../rules-1.14/kubernetes-storage.yaml | 217 + .../kubernetes-system-apiserver.yaml | 193 + .../kubernetes-system-controller-manager.yaml | 57 + .../kubernetes-system-kube-proxy.yaml | 57 + .../rules-1.14/kubernetes-system-kubelet.yaml | 385 + .../kubernetes-system-scheduler.yaml | 57 + .../rules-1.14/kubernetes-system.yaml | 87 + .../rules-1.14/node-exporter.rules.yaml | 188 + .../prometheus/rules-1.14/node-exporter.yaml | 801 ++ .../prometheus/rules-1.14/node-network.yaml | 55 + .../prometheus/rules-1.14/node.rules.yaml | 109 + .../rules-1.14/prometheus-operator.yaml | 253 + .../prometheus/rules-1.14/prometheus.yaml | 707 + .../rules-1.14/windows.node.rules.yaml | 301 + .../rules-1.14/windows.pod.rules.yaml | 158 + .../templates/prometheus/secret.yaml | 15 + .../templates/prometheus/service.yaml | 84 + .../prometheus/serviceThanosSidecar.yaml | 43 + .../serviceThanosSidecarExternal.yaml | 46 + .../templates/prometheus/serviceaccount.yaml | 21 + .../templates/prometheus/servicemonitor.yaml | 86 + .../servicemonitorThanosSidecar.yaml | 45 + .../templates/prometheus/servicemonitors.yaml | 47 + .../prometheus/serviceperreplica.yaml | 58 + .../templates/thanos-ruler/extrasecret.yaml | 20 + .../templates/thanos-ruler/ingress.yaml | 77 + .../thanos-ruler/podDisruptionBudget.yaml | 21 + .../templates/thanos-ruler/ruler.yaml | 199 + .../templates/thanos-ruler/secret.yaml | 26 + .../templates/thanos-ruler/service.yaml | 57 + .../thanos-ruler/serviceaccount.yaml | 20 + .../thanos-ruler/servicemonitor.yaml | 72 + .../charts/kube-prometheus-stack/values.yaml | 4736 +++++++ .../charts/prometheus-adapter/.helmignore | 21 + .../charts/prometheus-adapter/Chart.yaml | 23 + .../charts/prometheus-adapter/README.md | 160 + .../prometheus-adapter/ci/default-values.yaml | 0 .../ci/external-rules-values.yaml | 9 + .../prometheus-adapter/templates/NOTES.txt | 9 + .../prometheus-adapter/templates/_helpers.tpl | 84 + .../templates/certmanager.yaml | 82 + .../cluster-role-binding-auth-delegator.yaml | 20 + .../cluster-role-binding-auth-reader.yaml | 20 + .../cluster-role-binding-resource-reader.yaml | 20 + .../cluster-role-resource-reader.yaml | 24 + .../templates/configmap.yaml | 97 + .../templates/custom-metrics-apiservice.yaml | 34 + ...stom-metrics-cluster-role-binding-hpa.yaml | 24 + .../custom-metrics-cluster-role.yaml | 17 + .../templates/deployment.yaml | 149 + .../external-metrics-apiservice.yaml | 34 + ...rnal-metrics-cluster-role-binding-hpa.yaml | 20 + .../external-metrics-cluster-role.yaml | 20 + .../prometheus-adapter/templates/pdb.yaml | 23 + .../prometheus-adapter/templates/psp.yaml | 66 + .../resource-metrics-apiservice.yaml | 34 + ...resource-metrics-cluster-role-binding.yaml | 20 + .../resource-metrics-cluster-role.yaml | 23 + .../templates/role-binding-auth-reader.yaml | 21 + .../prometheus-adapter/templates/secret.yaml | 17 + .../prometheus-adapter/templates/service.yaml | 32 + .../templates/serviceaccount.yaml | 19 + .../charts/prometheus-adapter/values.yaml | 304 + .../{ => nova-3}/dev_omi_values.yaml | 0 .../nova-3/prod_omi_values.yaml | 182 + .../01-basic-setup-aws.cluster-config.yaml | 79 + .../samples/01-basic-setup-aws.values.yaml | 154 + .../nova-3/samples/02-basic-setup-gcp.yaml | 124 + .../nova-3/samples/03-basic-setup-onprem.yaml | 51 + .../nova-3/samples/README.md | 9 + .../nova-3/templates/NOTES.txt | 21 + .../nova-3/templates/_helpers.tpl | 29 + .../nova-3/templates/api/api.config.yaml | 64 + .../nova-3/templates/api/api.deployment.yaml | 89 + .../nova-3/templates/api/api.hpa.yaml | 31 + .../nova-3/templates/api/api.ingress.yaml | 24 + .../nova-3/templates/api/api.rbac.yaml | 42 + .../nova-3/templates/api/api.service.yaml | 34 + .../templates/engine/engine.config.yaml | 69 + .../templates/engine/engine.deployment.yaml | 132 + .../nova-3/templates/engine/engine.hpa.yaml | 73 + .../nova-3/templates/engine/engine.rbac.yaml | 49 + .../templates/engine/engine.service.yaml | 39 + .../license-proxy/license-proxy.config.yaml | 18 + .../license-proxy.deployment.yaml | 92 + .../license-proxy/license-proxy.rbac.yaml | 38 + .../license-proxy/license-proxy.service.yaml | 40 + .../volumes/aws/efs-model-download.job.yaml | 77 + .../nova-3/templates/volumes/aws/efs.pv.yaml | 24 + .../nova-3/templates/volumes/aws/efs.pvc.yaml | 15 + .../volumes/aws/efs.storageClass.yaml | 9 + .../nova-3/templates/volumes/gcp/gpd.pv.yaml | 22 + .../nova-3/templates/volumes/gcp/gpd.pvc.yaml | 16 + .../deepgram-self-hosted/nova-3/values.yaml | 798 ++ 480 files changed, 95627 insertions(+), 4 deletions(-) rename backend/charts/deepgram-self-hosted/{ => nova-2}/.helmignore (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/CHANGELOG.md (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/Chart.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/README.md (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/README.md.gotmpl (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/charts/cluster-autoscaler-9.46.0.tgz (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/charts/gpu-operator-v24.9.2.tgz (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/charts/kube-prometheus-stack-69.3.2.tgz (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/charts/prometheus-adapter-4.11.0.tgz (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/dev_omi_deepgram_grafana_alb_cert.yaml (100%) create mode 100644 backend/charts/deepgram-self-hosted/nova-2/dev_omi_values.yaml rename backend/charts/deepgram-self-hosted/{ => nova-2}/prod_omi_deepgram_grafana_alb_cert.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/prod_omi_values.yaml (98%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/samples/01-basic-setup-aws.cluster-config.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/samples/01-basic-setup-aws.values.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/samples/02-basic-setup-gcp.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/samples/03-basic-setup-onprem.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/samples/README.md (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/NOTES.txt (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/_helpers.tpl (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/api/api.config.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/api/api.deployment.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/api/api.hpa.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/api/api.ingress.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/api/api.rbac.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/api/api.service.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/engine/engine.config.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/engine/engine.deployment.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/engine/engine.hpa.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/engine/engine.rbac.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/engine/engine.service.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/license-proxy/license-proxy.config.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/license-proxy/license-proxy.deployment.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/license-proxy/license-proxy.rbac.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/license-proxy/license-proxy.service.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/volumes/aws/efs-model-download.job.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/volumes/aws/efs.pv.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/volumes/aws/efs.pvc.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/volumes/aws/efs.storageClass.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/volumes/gcp/gpd.pv.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/templates/volumes/gcp/gpd.pvc.yaml (100%) rename backend/charts/deepgram-self-hosted/{ => nova-2}/values.yaml (100%) create mode 100644 backend/charts/deepgram-self-hosted/nova-3/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/CHANGELOG.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/README.md.gotmpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md.gotmpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/extra-manifests.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/pdb.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/prometheusrule.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/vpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/crds/nfd-api-crds.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-certs.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-issuer.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/master.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-gc.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-master-conf.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-topologyupdater-conf.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-worker-conf.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/post-delete-job.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/prometheus.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater-crds.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/worker.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_clusterpolicies.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_nvidiadrivers.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/cleanup_crd.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/dcgm_exporter_config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/mig_config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nodefeaturerules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nvidiadriver.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/operator.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/plugin_config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/readonlyfs_scc.openshift.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/upgrade_crd.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.editorconfig create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/CONTRIBUTING.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagerconfigs.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagers.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-podmonitors.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-probes.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-prometheusagents.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-prometheuses.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-prometheusrules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-scrapeconfigs.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-servicemonitors.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-thanosrulers.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/default-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/with-affinity-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/with-dashboard-json-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/with-dashboard-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/with-extraconfigmapmounts-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/with-image-renderer-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/ci/with-persistence.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/dashboards/custom-dashboard.json create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/_config.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/_pod.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/configSecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/configmap-dashboard-provider.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/dashboards-json-configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/extra-manifests.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/headless-service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/hpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/image-renderer-deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/image-renderer-hpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/image-renderer-network-policy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/image-renderer-service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/image-renderer-servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/ingress.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/networkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/poddisruptionbudget.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/podsecuritypolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/pvc.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/secret-env.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/statefulset.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/tests/test-configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/tests/test-podsecuritypolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/tests/test-role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/tests/test-rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/tests/test-serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/templates/tests/test.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/grafana/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/ciliumnetworkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/crs-configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/extra-manifests.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/kubeconfig-secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/networkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/pdb.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/podsecuritypolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/psp-clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/rbac-configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/stsdiscovery-rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/templates/verticalpodautoscaler.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/kube-state-metrics/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/ci/port-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/daemonset.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/endpoints.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/extra-manifests.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/networkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/podmonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp-clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/psp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/rbac-configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/templates/verticalpodautoscaler.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-node-exporter/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/daemonset.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/podmonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/templates/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/prometheus-windows-exporter/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/alertmanager.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/extrasecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/ingress.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/ingressperreplica.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/podDisruptionBudget.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/psp-role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/psp-rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/psp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/alertmanager/serviceperreplica.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/core-dns/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/core-dns/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-api-server/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-controller-manager/endpoints.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-controller-manager/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-controller-manager/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-dns/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-dns/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-etcd/endpoints.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-etcd/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-etcd/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-proxy/endpoints.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-proxy/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-proxy/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-scheduler/endpoints.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-scheduler/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kube-scheduler/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/exporters/kubelet/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/extra-objects.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/configmap-dashboards.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/configmaps-datasources.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/alertmanager-overview.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/apiserver.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/cluster-total.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/controller-manager.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/etcd.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/grafana-overview.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-coredns.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-cluster.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-multicluster.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-namespace.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-node.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-pod.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-windows-cluster.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-windows-namespace.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-windows-pod.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workload.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-resources-workloads-namespace.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-windows-cluster-rsrc-use.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/k8s-windows-node-rsrc-use.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/kubelet.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-pod.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/namespace-by-workload.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-cluster-rsrc-use.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/node-rsrc-use.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes-darwin.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/nodes.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/persistentvolumesusage.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/pod-total.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus-remote-write.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/prometheus.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/proxy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/scheduler.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/grafana/dashboards-1.14/workload-total.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/_prometheus-operator.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/_prometheus-operator-webhook.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/deployment/deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/deployment/pdb.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/deployment/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/deployment/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-createSecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/ciliumnetworkpolicy-patchWebhook.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-createSecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/job-patchWebhook.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-createSecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/networkpolicy-patchWebhook.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/psp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/rolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/job-patch/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/mutatingWebhookConfiguration.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/admission-webhooks/validatingWebhookConfiguration.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/aggregate-clusterroles.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/certmanager.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/ciliumnetworkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/networkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/psp-clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/psp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus-operator/verticalpodautoscaler.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/_rules.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/additionalAlertRelabelConfigs.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/additionalAlertmanagerConfigs.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/additionalPrometheusRules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/additionalScrapeConfigs.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/ciliumnetworkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/csi-secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/extrasecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/ingress.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/ingressThanosSidecar.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/ingressperreplica.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/networkpolicy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/podDisruptionBudget.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/podmonitors.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/prometheus.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/psp-clusterrole.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/psp-clusterrolebinding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/psp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/alertmanager.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/config-reloaders.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/etcd.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/general.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.container_cpu_usage_seconds_total.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.container_memory_cache.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.container_memory_rss.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.container_memory_swap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.container_memory_working_set_bytes.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.container_resource.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/k8s.rules.pod_owner.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-availability.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-burnrate.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-histogram.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-apiserver-slos.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-general.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-prometheus-node-recording.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-scheduler.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kube-state-metrics.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubelet.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-apps.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-resources.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-storage.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-apiserver.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-controller-manager.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kube-proxy.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-kubelet.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system-scheduler.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/kubernetes-system.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/node-exporter.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/node-network.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/node.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus-operator.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/prometheus.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/windows.node.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/rules-1.14/windows.pod.rules.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/serviceThanosSidecar.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/serviceThanosSidecarExternal.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/servicemonitorThanosSidecar.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/servicemonitors.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/prometheus/serviceperreplica.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/extrasecret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/ingress.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/podDisruptionBudget.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/ruler.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/templates/thanos-ruler/servicemonitor.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/.helmignore create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/Chart.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/ci/default-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/ci/external-rules-values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/certmanager.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/cluster-role-binding-auth-delegator.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/cluster-role-binding-auth-reader.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/cluster-role-binding-resource-reader.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/cluster-role-resource-reader.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/configmap.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/custom-metrics-apiservice.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/custom-metrics-cluster-role-binding-hpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/custom-metrics-cluster-role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/external-metrics-apiservice.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/external-metrics-cluster-role-binding-hpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/external-metrics-cluster-role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/pdb.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/psp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/resource-metrics-apiservice.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/resource-metrics-cluster-role-binding.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/resource-metrics-cluster-role.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/role-binding-auth-reader.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/secret.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/templates/serviceaccount.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/charts/prometheus-adapter/values.yaml rename backend/charts/deepgram-self-hosted/{ => nova-3}/dev_omi_values.yaml (100%) create mode 100644 backend/charts/deepgram-self-hosted/nova-3/prod_omi_values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/samples/01-basic-setup-aws.cluster-config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/samples/01-basic-setup-aws.values.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/samples/02-basic-setup-gcp.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/samples/03-basic-setup-onprem.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/samples/README.md create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/NOTES.txt create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/_helpers.tpl create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/api/api.config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/api/api.deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/api/api.hpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/api/api.ingress.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/api/api.rbac.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/api/api.service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/engine/engine.config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/engine/engine.deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/engine/engine.hpa.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/engine/engine.rbac.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/engine/engine.service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/license-proxy/license-proxy.config.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/license-proxy/license-proxy.deployment.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/license-proxy/license-proxy.rbac.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/license-proxy/license-proxy.service.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/volumes/aws/efs-model-download.job.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/volumes/aws/efs.pv.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/volumes/aws/efs.pvc.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/volumes/aws/efs.storageClass.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/volumes/gcp/gpd.pv.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/templates/volumes/gcp/gpd.pvc.yaml create mode 100644 backend/charts/deepgram-self-hosted/nova-3/values.yaml diff --git a/backend/charts/deepgram-self-hosted/.helmignore b/backend/charts/deepgram-self-hosted/nova-2/.helmignore similarity index 100% rename from backend/charts/deepgram-self-hosted/.helmignore rename to backend/charts/deepgram-self-hosted/nova-2/.helmignore diff --git a/backend/charts/deepgram-self-hosted/CHANGELOG.md b/backend/charts/deepgram-self-hosted/nova-2/CHANGELOG.md similarity index 100% rename from backend/charts/deepgram-self-hosted/CHANGELOG.md rename to backend/charts/deepgram-self-hosted/nova-2/CHANGELOG.md diff --git a/backend/charts/deepgram-self-hosted/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-2/Chart.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/Chart.yaml rename to backend/charts/deepgram-self-hosted/nova-2/Chart.yaml diff --git a/backend/charts/deepgram-self-hosted/README.md b/backend/charts/deepgram-self-hosted/nova-2/README.md similarity index 100% rename from backend/charts/deepgram-self-hosted/README.md rename to backend/charts/deepgram-self-hosted/nova-2/README.md diff --git a/backend/charts/deepgram-self-hosted/README.md.gotmpl b/backend/charts/deepgram-self-hosted/nova-2/README.md.gotmpl similarity index 100% rename from backend/charts/deepgram-self-hosted/README.md.gotmpl rename to backend/charts/deepgram-self-hosted/nova-2/README.md.gotmpl diff --git a/backend/charts/deepgram-self-hosted/charts/cluster-autoscaler-9.46.0.tgz b/backend/charts/deepgram-self-hosted/nova-2/charts/cluster-autoscaler-9.46.0.tgz similarity index 100% rename from backend/charts/deepgram-self-hosted/charts/cluster-autoscaler-9.46.0.tgz rename to backend/charts/deepgram-self-hosted/nova-2/charts/cluster-autoscaler-9.46.0.tgz diff --git a/backend/charts/deepgram-self-hosted/charts/gpu-operator-v24.9.2.tgz b/backend/charts/deepgram-self-hosted/nova-2/charts/gpu-operator-v24.9.2.tgz similarity index 100% rename from backend/charts/deepgram-self-hosted/charts/gpu-operator-v24.9.2.tgz rename to backend/charts/deepgram-self-hosted/nova-2/charts/gpu-operator-v24.9.2.tgz diff --git a/backend/charts/deepgram-self-hosted/charts/kube-prometheus-stack-69.3.2.tgz b/backend/charts/deepgram-self-hosted/nova-2/charts/kube-prometheus-stack-69.3.2.tgz similarity index 100% rename from backend/charts/deepgram-self-hosted/charts/kube-prometheus-stack-69.3.2.tgz rename to backend/charts/deepgram-self-hosted/nova-2/charts/kube-prometheus-stack-69.3.2.tgz diff --git a/backend/charts/deepgram-self-hosted/charts/prometheus-adapter-4.11.0.tgz b/backend/charts/deepgram-self-hosted/nova-2/charts/prometheus-adapter-4.11.0.tgz similarity index 100% rename from backend/charts/deepgram-self-hosted/charts/prometheus-adapter-4.11.0.tgz rename to backend/charts/deepgram-self-hosted/nova-2/charts/prometheus-adapter-4.11.0.tgz diff --git a/backend/charts/deepgram-self-hosted/dev_omi_deepgram_grafana_alb_cert.yaml b/backend/charts/deepgram-self-hosted/nova-2/dev_omi_deepgram_grafana_alb_cert.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/dev_omi_deepgram_grafana_alb_cert.yaml rename to backend/charts/deepgram-self-hosted/nova-2/dev_omi_deepgram_grafana_alb_cert.yaml diff --git a/backend/charts/deepgram-self-hosted/nova-2/dev_omi_values.yaml b/backend/charts/deepgram-self-hosted/nova-2/dev_omi_values.yaml new file mode 100644 index 000000000..8553b46be --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-2/dev_omi_values.yaml @@ -0,0 +1,182 @@ +# See the Chart [README](https://github.com/deepgram/self-hosted-resources/blob/main/charts/deepgram-self-hosted#values) +# for documentation on all available options. + +global: + # pullSecretRef should refer to a K8s secret that + # must be created prior to installing this Chart. + # Consult the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/) for best practices on configuring Secrets for use in your cluster. + # + # You can create a secret for your image pull credentials + # with the following commands: + # ```bash + # docker login quay.io + # kubectl create secret docker-registry dg-regcred \ + # --docker-server=quay.io \ + # --docker-username='QUAY_DG_USER' \ + # --docker-password='QUAY_DG_PASSWORD' + # ``` + pullSecretRef: "dg-regcred" + + # deepgramSecretRef should refer to a K8s secret that + # must be created prior to installing this Chart. + # Consult the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/) for best practices on configuring Secrets for use in your cluster. + # + # You can create a secret for your Deepgram self-hosted API key + # with the following command: + # ```bash + # kubectl create secret generic dg-self-hosted-api-key --from-literal=DEEPGRAM_API_KEY='' + # ``` + deepgramSecretRef: "dg-self-hosted-api-key" + +scaling: + # -- Number of replicas to set during initial installation. + # @default -- `` + replicas: + api: 1 + engine: 1 + auto: + # Can toggle to true to enable autoscaling. Make sure to set a value for one of the available metrics + enabled: true + + api: + metrics: + # -- Scale the API deployment to this Engine-to-Api pod ratio + engineToApiRatio: 1 + + engine: + # -- Minimum number of Engine replicas. + minReplicas: 1 + # -- Maximum number of Engine replicas. + maxReplicas: 10 + metrics: + speechToText: + batch: + requestsPerPod: # Discuss a reasonable value with your Deepgram Account Representative + streaming: + requestsPerPod: 30 + textToSpeech: + batch: + requestsPerPod: # Discuss a reasonable value with your Deepgram Account Representative + # Discuss a reasoanble value with your Deepgram Account Representative + # Must also set engine.concurrencyLimit.activeRequests if using request ratio for autoscaling + requestCapacityRatio: + behavior: + scaleUp: + stabilizationWindowSeconds: 120 # Wait 2 minutes before scaling up + +api: + image: + path: us-central1-docker.pkg.dev/based-hardware-dev/deepgram/self-hosted-api + tag: release-250130 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s.deepgram.com/node-type + operator: In + values: + - api + ingress: + annotations: + kubernetes.io/ingress.class: "gce-internal" + kubernetes.io/ingress.regional-static-ip-name: "dev-omi-deepgram-ilb-ip-address" + kubernetes.io/ingress.allow-http: "false" + ingress.gcp.kubernetes.io/pre-shared-cert: "dev-omi-deepgram-ilb-cert" + hosts: + - host: dg.omiapi.com + paths: + - path: / + pathType: Prefix + + resources: + requests: + memory: "4Gi" + cpu: "2000m" + limits: + memory: "12Gi" + cpu: "4000m" + +engine: + image: + path: us-central1-docker.pkg.dev/based-hardware-dev/deepgram/self-hosted-engine + tag: release-250130 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s.deepgram.com/node-type + operator: In + values: + - engine + resources: + requests: + memory: "24Gi" + cpu: "5000m" + gpu: 1 + limits: + memory: "40Gi" + cpu: "12000m" + gpu: 1 + # Discuss a reasonable value with your Deepgram Account Representative + # If not using autoscaling, can be left empty, but must be set if using + # autoscaling with scaling.auto.engine.metrics.requestCapacityRatio + concurrencyLimit: + activeRequests: + modelManager: + volumes: + gcp: + gpd: + enabled: true + # Replace with your Google disk handle + volumeHandle: "projects/based-hardware-dev/zones/us-central1-a/disks/dev-omi-deepgram-model-storage" + +licenseProxy: + enabled: true + image: + path: us-central1-docker.pkg.dev/based-hardware-dev/deepgram/self-hosted-license-proxy + tag: release-250130 + affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: k8s.deepgram.com/node-type + operator: In + values: + - license-proxy + resources: + requests: + memory: "4Gi" + cpu: "1000m" + limits: + memory: "8Gi" + cpu: "2000m" + +gpu-operator: + # GKE will manage the driver and toolkit installation for us by default. + enabled: false + +kube-prometheus-stack: + grafana: + enabled: true + ingress: + enabled: true + annotations: + kubernetes.io/ingress.class: "gce" + kubernetes.io/ingress.global-static-ip-name: "dev-omi-deepgram-grafana-alb-ip-address" + networking.gke.io/managed-certificates: "dev-omi-deepgram-grafana-alb-cert" + kubernetes.io/ingress.allow-http: "false" + hosts: + - dg-monitor.omiapi.com + path: / + persistence: + enabled: true + type: sts + storageClassName: standard-rwo + accessModes: + - ReadWriteOnce + size: 20Gi + finalizers: + - kubernetes.io/pvc-protection diff --git a/backend/charts/deepgram-self-hosted/prod_omi_deepgram_grafana_alb_cert.yaml b/backend/charts/deepgram-self-hosted/nova-2/prod_omi_deepgram_grafana_alb_cert.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/prod_omi_deepgram_grafana_alb_cert.yaml rename to backend/charts/deepgram-self-hosted/nova-2/prod_omi_deepgram_grafana_alb_cert.yaml diff --git a/backend/charts/deepgram-self-hosted/prod_omi_values.yaml b/backend/charts/deepgram-self-hosted/nova-2/prod_omi_values.yaml similarity index 98% rename from backend/charts/deepgram-self-hosted/prod_omi_values.yaml rename to backend/charts/deepgram-self-hosted/nova-2/prod_omi_values.yaml index d5a18350f..f4fcfd36b 100644 --- a/backend/charts/deepgram-self-hosted/prod_omi_values.yaml +++ b/backend/charts/deepgram-self-hosted/nova-2/prod_omi_values.yaml @@ -45,7 +45,7 @@ scaling: engine: # -- Minimum number of Engine replicas. - minReplicas: 2 + minReplicas: 3 # -- Maximum number of Engine replicas. maxReplicas: 10 metrics: @@ -67,7 +67,7 @@ scaling: api: image: path: us-central1-docker.pkg.dev/based-hardware/deepgram/self-hosted-api - tag: release-250331 + tag: release-250130 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -100,7 +100,7 @@ api: engine: image: path: us-central1-docker.pkg.dev/based-hardware/deepgram/self-hosted-engine - tag: release-250331 + tag: release-250130 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: @@ -136,7 +136,7 @@ licenseProxy: enabled: true image: path: us-central1-docker.pkg.dev/based-hardware/deepgram/self-hosted-license-proxy - tag: release-250331 + tag: release-250130 affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: diff --git a/backend/charts/deepgram-self-hosted/samples/01-basic-setup-aws.cluster-config.yaml b/backend/charts/deepgram-self-hosted/nova-2/samples/01-basic-setup-aws.cluster-config.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/samples/01-basic-setup-aws.cluster-config.yaml rename to backend/charts/deepgram-self-hosted/nova-2/samples/01-basic-setup-aws.cluster-config.yaml diff --git a/backend/charts/deepgram-self-hosted/samples/01-basic-setup-aws.values.yaml b/backend/charts/deepgram-self-hosted/nova-2/samples/01-basic-setup-aws.values.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/samples/01-basic-setup-aws.values.yaml rename to backend/charts/deepgram-self-hosted/nova-2/samples/01-basic-setup-aws.values.yaml diff --git a/backend/charts/deepgram-self-hosted/samples/02-basic-setup-gcp.yaml b/backend/charts/deepgram-self-hosted/nova-2/samples/02-basic-setup-gcp.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/samples/02-basic-setup-gcp.yaml rename to backend/charts/deepgram-self-hosted/nova-2/samples/02-basic-setup-gcp.yaml diff --git a/backend/charts/deepgram-self-hosted/samples/03-basic-setup-onprem.yaml b/backend/charts/deepgram-self-hosted/nova-2/samples/03-basic-setup-onprem.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/samples/03-basic-setup-onprem.yaml rename to backend/charts/deepgram-self-hosted/nova-2/samples/03-basic-setup-onprem.yaml diff --git a/backend/charts/deepgram-self-hosted/samples/README.md b/backend/charts/deepgram-self-hosted/nova-2/samples/README.md similarity index 100% rename from backend/charts/deepgram-self-hosted/samples/README.md rename to backend/charts/deepgram-self-hosted/nova-2/samples/README.md diff --git a/backend/charts/deepgram-self-hosted/templates/NOTES.txt b/backend/charts/deepgram-self-hosted/nova-2/templates/NOTES.txt similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/NOTES.txt rename to backend/charts/deepgram-self-hosted/nova-2/templates/NOTES.txt diff --git a/backend/charts/deepgram-self-hosted/templates/_helpers.tpl b/backend/charts/deepgram-self-hosted/nova-2/templates/_helpers.tpl similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/_helpers.tpl rename to backend/charts/deepgram-self-hosted/nova-2/templates/_helpers.tpl diff --git a/backend/charts/deepgram-self-hosted/templates/api/api.config.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/api/api.config.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/api/api.config.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/api/api.config.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/api/api.deployment.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/api/api.deployment.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/api/api.deployment.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/api/api.deployment.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/api/api.hpa.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/api/api.hpa.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/api/api.hpa.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/api/api.hpa.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/api/api.ingress.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/api/api.ingress.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/api/api.ingress.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/api/api.ingress.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/api/api.rbac.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/api/api.rbac.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/api/api.rbac.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/api/api.rbac.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/api/api.service.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/api/api.service.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/api/api.service.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/api/api.service.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/engine/engine.config.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.config.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/engine/engine.config.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.config.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/engine/engine.deployment.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.deployment.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/engine/engine.deployment.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.deployment.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/engine/engine.hpa.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.hpa.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/engine/engine.hpa.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.hpa.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/engine/engine.rbac.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.rbac.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/engine/engine.rbac.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.rbac.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/engine/engine.service.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.service.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/engine/engine.service.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/engine/engine.service.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.config.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.config.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.config.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.config.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.deployment.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.deployment.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.deployment.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.deployment.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.rbac.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.rbac.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.rbac.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.rbac.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.service.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.service.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/license-proxy/license-proxy.service.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/license-proxy/license-proxy.service.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/volumes/aws/efs-model-download.job.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs-model-download.job.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/volumes/aws/efs-model-download.job.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs-model-download.job.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/volumes/aws/efs.pv.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs.pv.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/volumes/aws/efs.pv.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs.pv.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/volumes/aws/efs.pvc.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs.pvc.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/volumes/aws/efs.pvc.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs.pvc.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/volumes/aws/efs.storageClass.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs.storageClass.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/volumes/aws/efs.storageClass.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/volumes/aws/efs.storageClass.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/volumes/gcp/gpd.pv.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/volumes/gcp/gpd.pv.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/volumes/gcp/gpd.pv.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/volumes/gcp/gpd.pv.yaml diff --git a/backend/charts/deepgram-self-hosted/templates/volumes/gcp/gpd.pvc.yaml b/backend/charts/deepgram-self-hosted/nova-2/templates/volumes/gcp/gpd.pvc.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/templates/volumes/gcp/gpd.pvc.yaml rename to backend/charts/deepgram-self-hosted/nova-2/templates/volumes/gcp/gpd.pvc.yaml diff --git a/backend/charts/deepgram-self-hosted/values.yaml b/backend/charts/deepgram-self-hosted/nova-2/values.yaml similarity index 100% rename from backend/charts/deepgram-self-hosted/values.yaml rename to backend/charts/deepgram-self-hosted/nova-2/values.yaml diff --git a/backend/charts/deepgram-self-hosted/nova-3/.helmignore b/backend/charts/deepgram-self-hosted/nova-3/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/backend/charts/deepgram-self-hosted/nova-3/CHANGELOG.md b/backend/charts/deepgram-self-hosted/nova-3/CHANGELOG.md new file mode 100644 index 000000000..9cf676c1e --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/CHANGELOG.md @@ -0,0 +1,201 @@ +# Changelog + +All notable changes to this Helm chart will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +## [0.12.0] - 2025-03-31 + +### Added + +- Updated default container tags to March 2025 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-march-2025-release-250331) for additional details. + + +## [0.11.1] - 2025-03-28 + +### Added + +- Exposed configuration values to enable named-entity recognition models. See the [March 2025 Deepgram Self-Hosted Changelog](https://deepgram.com/changelog/deepgram-self-hosted-march-2025-release-250307) for more details on features powered by these models. + +## [0.11.0] - 2025-03-07 + +### Added + +- Updated default container tags to March 2025 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-march-2025-release-250307) for additional details. + +## [0.10.0] - 2025-01-30 + +### Added + +- Updated default container tags to January 2025 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-january-2025-release-250130) for additional details. + +## [0.9.0] - 2024-12-26 + +### Added + +- Updated default container tags to December 2024 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-december-2024-release-241226) for additional details. + +## [0.8.1] - 2024-12-17 + +### Changed + +- Fixed default ratio metrics in Prometheus Adapter chart values to use 0.0 to 1.0 scale to match autoscaling documentation + +## [0.8.0] - 2024-11-21 + +### Added + +- Updated default container tags to November 2024 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-november-2024-release-241121) for additional details. + +### Fixed + +- Add the Engine Deployment tolerations to the Engine's model download Job. + +## [0.7.0] - 2024-10-24 + +### Added + +- Updated default container tags to October 2024 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-october-2024-release-241024) for additional details. Highlights include: + - Adds new [streaming websocket TTS](https://deepgram.com/changelog/websocket-text-to-speech-api)! This is a software feature, so no new TTS models are required. + +### Changed + +- AWS samples updated to take advantage of new [EKS accelerated AMIs](https://aws.amazon.com/about-aws/whats-new/2024/10/amazon-eks-nvidia-aws-neuron-instance-types-al2023/), which bundle the required NVIDIA driver and toolkit instead of being installed by the NVIDIA GPU operator + +## [0.6.0] - 2024-09-27 + +### Added + +- Updated default container tags to September 2024 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-september-2024-release-240927) for additional details. Highlights include: + - Adds broader support in Engine container for model auto-loading during runtime. + - Filesystems that don't support `inotify`, such as `nfs`/`csi` PersistentVolumes in Kubernetes, can now load and unload models during runtime without requiring a Pod restart. +- Automatic model management on AWS now supports model removal. See the `engine.modelManager.models.remove` section in the `values.yaml` file for details. +- Container orchestrator environment variable added to improve support. + +### Changed + +- Automatic model downloads on AWS are moved from `engine.modelManager.models.links` to `engine.modelManager.models.add`. The old `links` field is still supported, but migration is recommended. + +### Fixed + +- Update sample files to fix an issue with sample command for Kubernetes Secret creation storing Quay credential + - Previous command used `--from-file` with the user's Docker configuration file. Some local secret managers, like + Apple Keychain, scrub this file for sensitive information, which would result in an empty secret being created. + +## [0.5.0] - 2024-08-27 + +### Added + +- Updated default container tags to August 2024 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-august-2024-release-240827) for additional details. Highlights include: + - GA support for entity detection for pre-recorded English audio + - GA support for improved redaction for pre-recorded English audio + +### Fixed + +- Fixed a misleading comment in the `03-basic-setup-onprem.yaml` sample file that wrongly suggested `engine.modelManager.volumes.customVolumeClaim.name` should be a `PersistentVolume` instead of a `PersistentVolumeClaim` + +### Changed + +- Deepgram's core products are available to host both on-premises and in the cloud. Official resources have been updated to refer to a ["self-hosted" product offering](https://deepgram.com/self-hosted), instead of an "onprem" product offering, to align the product name with industry naming standards. The Deepgram Quay image repository names have been updated to reflect this. + +## [0.4.0] - 2024-07-25 + +### Added + +- Introduced entity detection feature flag for API containers (`false` by default). +- Updated default container tags to July 2024 release. Refer to the [main Deepgram changelog](https://deepgram.com/changelog/deepgram-self-hosted-july-2024-release-240725) for additional details. Highlights include: + - Support for Deepgram's new English/Spanish multilingual code-switching model + - Beta support for entity detection for pre-recorded English audio + - Beta support for improved redaction for pre-recorded English audio + - Beta support for improved entity formatting for streaming English audio + +### Removed + +- Removed some items nested under `api.features` and `engine.features` sections in favor of opinionated defaults. + +## [0.3.0] - 2024-07-18 + +### Added + +- Allow specifying custom annotations for deployments. + +## [0.2.3] - 2024-07-15 + +### Added + +- Sample `values.yaml` file for on-premises/self-managed Kubernetes clusters. + +### Fixed + +- Resolves a mismatch between PVC and SC prefix naming convention. +- Resolves error when specifying custom service account names. + +### Changed + +- Make `imagePullSecrets` optional. + +## [0.2.2-beta] - 2024-06-27 + +### Added + +- Adds more verbose logging for audio content length. +- Keeps our software up-to-date. +- See the [changelog](https://deepgram.com/changelog/deepgram-on-premises-june-2024-release-240627) associated with this routine monthly release. + +## [0.2.1-beta] - 2024-06-24 + +### Added + +- Restart Deepgram containers automatically when underlying ConfigMaps have been modified. + +## [0.2.0-beta] - 2024-06-20 + +### Added +- Support for managing node autoscaling with [cluster-autoscaler](https://github.com/kubernetes/autoscaler). +- Support for pod autoscaling of Deepgram components. +- Support for keeping the upstream Deepgram License server as a backup even when the License Proxy is deployed. See `licenseProxy.keepUpstreamServerAsBackup` for details. + +### Changed + +- Initial installation replica count values moved from `scaling.static.{api,engine}.replicas` to `scaling.replicas.{api,engine}`. +- License Proxy is no longer manually scaled. Instead, scaling can be indirectly controlled via `licenseProxy.{enabled,deploySecondReplica}`. +- Labels for Deepgram dedicated nodes in the sample `cluster-config.yaml` for AWS, and the `nodeAffinity` sections of the sample `values.yaml` files. The key has been renamed from `deepgram/nodeType` to `k8s.deepgram.com/node-type`, and the values are no longer prepended with `deepgram`. +- AWS EFS model download job hook delete policy changed to `before-hook-creation`. +- Concurrency limit moved from API (`api.concurrencyLimit.activeRequests`) to Engine level (`engine.concurrencyLimit.activeRequests`). + +## [0.1.1-alpha] - 2024-06-03 + +### Added + +- Various documentation improvements + +## [0.1.0-alpha] - 2024-05-31 + +### Added + +- Initial implementation of the Helm chart. + + +[unreleased]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.12.0...HEAD +[0.12.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.11.1...0.12.0 +[0.11.1]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.11.0...0.11.1 +[0.11.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.10.0...deepgram-self-hosted-0.11.0 +[0.10.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.9.0...deepgram-self-hosted-0.10.0 +[0.9.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.8.1...deepgram-self-hosted-0.9.0 +[0.8.1]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.8.0...deepgram-self-hosted-0.8.1 +[0.8.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.7.0...deepgram-self-hosted-0.8.0 +[0.7.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.6.0...deepgram-self-hosted-0.7.0 +[0.6.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.5.0...deepgram-self-hosted-0.6.0 +[0.5.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.4.0...deepgram-self-hosted-0.5.0 +[0.4.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.3.0...deepgram-self-hosted-0.4.0 +[0.3.0]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.2.3...deepgram-self-hosted-0.3.0 +[0.2.3]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.2.2-beta...deepgram-self-hosted-0.2.3 +[0.2.2-beta]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.2.1-beta...deepgram-self-hosted-0.2.2-beta +[0.2.1-beta]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.2.0-beta...deepgram-self-hosted-0.2.1-beta +[0.2.0-beta]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.1.1-alpha...deepgram-self-hosted-0.2.0-beta +[0.1.1-alpha]: https://github.com/deepgram/self-hosted-resources/compare/deepgram-self-hosted-0.1.0-alpha...deepgram-self-hosted-0.1.1-alpha +[0.1.0-alpha]: https://github.com/deepgram/self-hosted-resources/releases/tag/deepgram-self-hosted-0.1.0-alpha + + diff --git a/backend/charts/deepgram-self-hosted/nova-3/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-3/Chart.yaml new file mode 100644 index 000000000..4cc013fe9 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/Chart.yaml @@ -0,0 +1,42 @@ +apiVersion: v2 +appVersion: release-250331 +dependencies: +- condition: gpu-operator.enabled + name: gpu-operator + repository: https://helm.ngc.nvidia.com/nvidia + version: ^24.3.0 +- condition: cluster-autoscaler.enabled + name: cluster-autoscaler + repository: https://kubernetes.github.io/autoscaler + version: ^9.37.0 +- condition: kube-prometheus-stack.includeDependency,scaling.auto.enabled + name: kube-prometheus-stack + repository: https://prometheus-community.github.io/helm-charts + version: ^60.2.0 +- condition: prometheus-adapter.includeDependency,scaling.auto.enabled + name: prometheus-adapter + repository: https://prometheus-community.github.io/helm-charts + version: ^4.10.0 +description: A Helm chart for running Deepgram services in a self-hosted environment +home: https://developers.deepgram.com/docs/self-hosted-introduction +icon: https://www.dropbox.com/scl/fi/v4jtfbsrx881pbevcga3j/D-icon-black-square-250x250.png?rlkey=barv5jeuhd7t2lczz0m3nane7&dl=1 +keywords: +- voice ai +- text-to-speech +- tts +- aura +- speech-to-text +- stt +- asr +- nova +- voice agent +- self-hosted +kubeVersion: '>=1.28.0-0' +maintainers: +- email: self.hosted@deepgram.com + name: Deepgram Self-Hosted +name: deepgram-self-hosted +sources: +- https://github.com/deepgram/self-hosted-resources +type: application +version: 0.12.0 diff --git a/backend/charts/deepgram-self-hosted/nova-3/README.md b/backend/charts/deepgram-self-hosted/nova-3/README.md new file mode 100644 index 000000000..82abcd6f4 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/README.md @@ -0,0 +1,331 @@ +# deepgram-self-hosted + +![Version: 0.12.0](https://img.shields.io/badge/Version-0.12.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: release-250331](https://img.shields.io/badge/AppVersion-release--250331-informational?style=flat-square) [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/deepgram-self-hosted)](https://artifacthub.io/packages/search?repo=deepgram-self-hosted) + +A Helm chart for running Deepgram services in a self-hosted environment + +**Homepage:** + +**Deepgram Self-Hosted Kubernetes Guides:** + +## Source Code + +* + +## Requirements + +Kubernetes: `>=1.28.0-0` + +| Repository | Name | Version | +|------------|------|---------| +| https://helm.ngc.nvidia.com/nvidia | gpu-operator | ^24.3.0 | +| https://kubernetes.github.io/autoscaler | cluster-autoscaler | ^9.37.0 | +| https://prometheus-community.github.io/helm-charts | kube-prometheus-stack | ^60.2.0 | +| https://prometheus-community.github.io/helm-charts | prometheus-adapter | ^4.10.0 | + +## Using the Chart + +### Get Repository Info + +```bash +helm repo add deepgram https://deepgram.github.io/self-hosted-resources +helm repo update +``` + +### Installing the Chart + +The Deepgram self-hosted chart requires Helm 3.7+ in order to install successfully. Please check your helm release before installation. + +You will need to provide your [self-service Deepgram licensing and credentials](https://developers.deepgram.com/docs/self-hosted-self-service-tutorial) information. See `global.deepgramSecretRef` and `global.pullSecretRef` in the [Values section](#values) for more details, and the [Deepgram Self-Hosted Kubernetes Guides](https://developers.deepgram.com/docs/kubernetes) for instructions on how to create these secrets. + +You may also override any default configuration values. See [the Values section](#values) for a list of available options, and the [samples directory](./samples) for examples of a standard installation. + +``` +helm install -f my-values.yaml [RELEASE_NAME] deepgram/deepgram-self-hosted --atomic --timeout 45m +``` + +### Upgrade and Rollback Strategies + +To upgrade the Deepgram components to a new version, follow these steps: + +1. Update the various `image.tag` values in the `values.yaml` file to the desired version. + +2. Run the Helm upgrade command: + + ```bash + helm upgrade -f my-values.yaml [RELEASE_NAME] deepgram/deepgram-self-hosted --atomic --timeout 60m + ``` + +If you encounter any issues during the upgrade process, you can perform a rollback to the previous version: + +```bash +helm rollback deepgram +``` + +Before upgrading, ensure that you have reviewed the release notes and any migration guides provided by Deepgram for the specific version you are upgrading to. + +### Uninstalling the Chart + +```bash +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +## Changelog + +See the [chart CHANGELOG](./CHANGELOG.md) for a list of relevant changes for each version of the Helm chart. + +For more details on changes to the underlying Deepgram resources, such as the container images or available models, see the [official Deepgram changelog](https://deepgram.com/changelog) ([RSS feed](https://deepgram.com/changelog.xml)). + +## Chart Configuration + +### Persistent Storage Options + +The Deepgram Helm chart supports different persistent storage options for storing Deepgram models and data. The available options include: + +- AWS Elastic File System (EFS) +- Google Cloud Persistent Disk (GPD) +- Custom PersistentVolumeClaim (PVC) + +To configure a specific storage option, see the `engine.modelManager.volumes` [configuration values](#values). Make sure to provide the necessary configuration values for the selected storage option, such as the EFS file system ID or the GPD disk type and size. + +For detailed instructions on setting up and configuring each storage option, refer to the [Deepgram self-hosted guides](https://developers.deepgram.com/docs/kubernetes) and the respective cloud provider's documentation. + +### Autoscaling + +Autoscaling your cluster's capacity to meet incoming traffic demands involves both node autoscaling and pod autoscaling. Node autoscaling for supported cloud providers is setup by default when using this Helm chart and creating your cluster with the [Deepgram self-hosted guides](https://developers.deepgram.com/docs/kubernetes). Pod autoscaling can be enabled via the `scaling.auto.enabled` configuration option in this chart. + +#### Engine + +The Engine component is the core of the Deepgram self-hosted platform, responsible for performing inference using your deployed models. Autoscaling increases the number of Engine replicas to maintain consistent performance for incoming traffic. + +There are currently two primary ways to scale the Engine component: scaling with a hard request limit per Engine Pod, or scaling with a soft request limit per Engine pod. + +To set a hard limit on which to scale, configure `engine.concurrencyLimit.activeRequests` and `scaling.auto.engine.metrics.requestCapacityRatio`. The `activeRequests` parameter will set a hard limit of how many requests any given Engine pod will accept, and the `requestCapacityRatio` will govern scaling the Engine deployment when a certain percentage of "available request slots" is filled. For example, a requestCapacityRatio of `0.8` will scale the Engine deployment when the current number of active requests is >=80% of the active request concurrency limit. If the cluster is not able to scale in time and current active requests hits 100% of the preset limit, additional client requests to the API will return a `429 Too Many Requests` HTTP response to clients. This hard limit means that if a request is accepted for inference, it will have consistent performance, as the cluster will refuse surplus requests that could overload the cluster and degrade performance, at the expense of possibly rejecting some incoming requests if capacity does not scale in time. + +To set a soft limit on which to scale, configure `scaling.auto.engine.metrics.{speechToText,textToSpeech}.{batch,streaming}.requestsPerPod`, depending on the primary traffic source for your environment. The cluster will attempt to scale to meet this target for number of requests per Engine pod, but will not reject extra requests with a `429 Too Many Request` HTTP response like the hard limit will. If the number of extra requests increases faster than the cluster can scale additional capacity, all incoming requests will still be accepted, but the performance of individual requests may degrade. + +> [!NOTE] +> Deepgram recommends provisioning separate environments for batch speech-to-text, streaming speech-to-text, and text-to-speech workloads because typical latency and throughput tradeoffs are different for each of those use cases. + +There is also a `scaling.auto.engine.metrics.custom` configuration value available to define your own custom scaling metric, if needed. + +#### API + +The API component is responsible for accepting incoming requests and forming responses, delegating inference work to the Deepgram Engine as needed. A single API pod can typically handle delegating requests to multiple Engine pods, so it is more compute efficient to deploy fewer API pods relative to the number of Engine pods. The `scaling.auto.api.metrics.engineToApiRatio` configuration value defines the ratio between Engine to API pods. The default value is appropriate for most deployments. + +There is also a `scaling.auto.api.metrics.custom` configuration value available to define your own custom scaling metric, if needed. + +#### License Proxy + +The [License Proxy](https://developers.deepgram.com/docs/license-proxy) is intended to be deployed as a fixed-scale deployment the proxies all licensing requests from your environment. It should not be upscaled with the traffic demands of your environment. + +This chart deploys one License Proxy Pod per environment by default. If you wish to deploy a second License Proxy Pod for redundancy, set `licenseProxy.deploySecondReplica` to `true`. + +### RBAC Configuration + +Role-Based Access Control (RBAC) is used to control access to Kubernetes resources based on the roles and permissions assigned to users or service accounts. The Deepgram Helm chart includes default RBAC roles and bindings for the API, Engine, and License Proxy components. + +To use custom RBAC roles and bindings based on your specific security requirements, you can individually specify pre-existing ServiceAccounts to bind to each deployment by specifying the following options in `values.yaml`: + +``` +{api|engine|licenseProxy}.serviceAccount.create=false +{api|engine|licenseProxy}.serviceAccount.name= +``` + +Make sure to review and adjust the RBAC configuration according to the principle of least privilege, granting only the necessary permissions for each component. + +### Secret Management + +The Deepgram Helm chart takes references to two existing secrets - one containing your distribution credentials to pull container images from Deepgram's image repository, and one containing your Deepgram self-hosted API key. + +Consult the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/) for best practices on configuring Secrets for use in your cluster. + +## Getting Help + +See the [Getting Help](../../README.md#getting-help) section in the root of this repository for a list of resources to help you troubleshoot and resolve issues. + +### Troubleshooting + +If you encounter issues while deploying or using Deepgram, consider the following troubleshooting steps: + +1. Check the pod status and logs: + - Use `kubectl get pods` to check the status of the Deepgram pods. + - Use `kubectl logs ` to view the logs of a specific pod. + +2. Verify resource availability: + - Ensure that the cluster has sufficient CPU, memory, and storage resources to accommodate the Deepgram components. + - Check for any resource constraints or limits imposed by the namespace or the cluster. + +3. Review the Kubernetes events: + - Use `kubectl get events` to view any events or errors related to the Deepgram deployment. + +4. Check the network connectivity: + - Verify that the Deepgram components can communicate with each other and with the Deepgram license server (license.deepgram.com). + - Check the network policies and firewall rules to ensure that the necessary ports and protocols are allowed. + +5. Collect diagnostic information: + - Gather relevant logs and metrics. + - Export your existing Helm chart values: + ```bash + helm get values [RELEASE_NAME] > my-deployed-values.yaml + ``` + - Provide the collected diagnostic information to Deepgram for assistance. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| api.additionalAnnotations | object | `nil` | Additional annotations to add to the API deployment | +| api.additionalLabels | object | `{}` | Additional labels to add to API resources | +| api.affinity | object | `{}` | [Affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) to apply for API pods. | +| api.driverPool | object | `` | driverPool configures the backend pool of speech engines (generically referred to as "drivers" here). The API will load-balance among drivers in the standard pool; if one standard driver fails, the next one will be tried. | +| api.driverPool.standard | object | `` | standard is the main driver pool to use. | +| api.driverPool.standard.maxResponseSize | string | `"1073741824"` | Maximum response to deserialize from Driver (in bytes). Default is 1GB, expressed in bytes. | +| api.driverPool.standard.retryBackoff | float | `1.6` | retryBackoff is the factor to increase the retrySleep by for each additional retry (for exponential backoff). | +| api.driverPool.standard.retrySleep | string | `"2s"` | retrySleep defines the initial sleep period (in humantime duration) before attempting a retry. | +| api.driverPool.standard.timeoutBackoff | float | `1.2` | timeoutBackoff is the factor to increase the timeout by for each additional retry (for exponential backoff). | +| api.features | object | `` | Enable ancillary features | +| api.features.diskBufferPath | string | `nil` | If API is receiving requests faster than Engine can process them, a request queue will form. By default, this queue is stored in memory. Under high load, the queue may grow too large and cause Out-Of-Memory errors. To avoid this, set a diskBufferPath to buffer the overflow on the request queue to disk. WARN: This is only to temporarily buffer requests during high load. If there is not enough Engine capacity to process the queued requests over time, the queue (and response time) will grow indefinitely. | +| api.features.entityDetection | bool | `false` | Enables entity detection on pre-recorded audio *if* a valid entity detection model is available. | +| api.features.entityRedaction | bool | `false` | Enables entity-based redaction on pre-recorded audio *if* a valid entity detection model is available. | +| api.features.formatEntityTags | bool | `false` | Enables format entity tags on pre-recorded audio *if* a valid NER model is available. | +| api.image.path | string | `"quay.io/deepgram/self-hosted-api"` | path configures the image path to use for creating API containers. You may change this from the public Quay image path if you have imported Deepgram images into a private container registry. | +| api.image.pullPolicy | string | `"IfNotPresent"` | pullPolicy configures how the Kubelet attempts to pull the Deepgram API image | +| api.image.tag | string | `"release-250331"` | tag defines which Deepgram release to use for API containers | +| api.livenessProbe | object | `` | Liveness probe customization for API pods. | +| api.namePrefix | string | `"deepgram-api"` | namePrefix is the prefix to apply to the name of all K8s objects associated with the Deepgram API containers. | +| api.readinessProbe | object | `` | Readiness probe customization for API pods. | +| api.resolver | object | `` | Specify custom DNS resolution options. | +| api.resolver.maxTTL | int | `nil` | maxTTL sets the DNS TTL value if specifying a custom DNS nameserver. | +| api.resolver.nameservers | list | `[]` | nameservers allows for specifying custom domain name server(s). A valid list item's format is "{IP} {PORT} {PROTOCOL (tcp or udp)}", e.g. `"127.0.0.1 53 udp"`. | +| api.resources | object | `` | Configure resource limits per API container. See [Deepgram's documentation](https://developers.deepgram.com/docs/self-hosted-deployment-environments#api) for more details. | +| api.securityContext | object | `{}` | [Security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for API pods. | +| api.server | object | `` | Configure how the API will listen for your requests | +| api.server.callbackConnTimeout | string | `"1s"` | callbackConnTimeout configures how long to wait for a connection to a callback URL. See [Deepgram's callback documentation](https://developers.deepgram.com/docs/callback) for more details. The value should be a humantime duration. | +| api.server.callbackTimeout | string | `"10s"` | callbackTimeout configures how long to wait for a response from a callback URL. See [Deepgram's callback documentation](https://developers.deepgram.com/docs/callback) for more details. The value should be a humantime duration. | +| api.server.fetchConnTimeout | string | `"1s"` | fetchConnTimeout configures how long to wait for a connection to a fetch URL. The value should be a humantime duration. A fetch URL is a URL passed in an inference request from which a payload should be downloaded. | +| api.server.fetchTimeout | string | `"60s"` | fetchTimeout configures how long to wait for a response from a fetch URL. The value should be a humantime duration. A fetch URL is a URL passed in an inference request from which a payload should be downloaded. | +| api.server.host | string | `"0.0.0.0"` | host is the IP address to listen on. You will want to listen on all interfaces to interact with other pods in the cluster. | +| api.server.port | int | `8080` | port to listen on. | +| api.serviceAccount.create | bool | `true` | Specifies whether to create a default service account for the Deepgram API Deployment. | +| api.serviceAccount.name | string | `nil` | Allows providing a custom service account name for the API component. If left empty, the default service account name will be used. If specified, and `api.serviceAccount.create = true`, this defines the name of the default service account. If specified, and `api.serviceAccount.create = false`, this provides the name of a preconfigured service account you wish to attach to the API deployment. | +| api.tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) to apply to API pods. | +| api.updateStrategy.rollingUpdate.maxSurge | int | `1` | The maximum number of extra API pods that can be created during a rollingUpdate, relative to the number of replicas. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-surge) for more details. | +| api.updateStrategy.rollingUpdate.maxUnavailable | int | `0` | The maximum number of API pods, relative to the number of replicas, that can go offline during a rolling update. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable) for more details. | +| cluster-autoscaler.autoDiscovery.clusterName | string | `nil` | Name of your AWS EKS cluster. Using the [Cluster Autoscaler](https://github.com/kubernetes/autoscaler) on AWS requires knowledge of certain cluster metadata. | +| cluster-autoscaler.awsRegion | string | `nil` | Region of your AWS EKS cluster. Using the [Cluster Autoscaler](https://github.com/kubernetes/autoscaler) on AWS requires knowledge of certain cluster metadata. | +| cluster-autoscaler.enabled | bool | `false` | Set to `true` to enable node autoscaling with AWS EKS. Note needed for GKE, as autoscaling is enabled by a [cli option on cluster creation](https://cloud.google.com/kubernetes-engine/docs/how-to/cluster-autoscaler#creating_a_cluster_with_autoscaling). | +| cluster-autoscaler.rbac.serviceAccount.annotations."eks.amazonaws.com/role-arn" | string | `nil` | Replace with the AWS Role ARN configured for the Cluster Autoscaler. See the [Deepgram AWS EKS guide](https://developers.deepgram.com/docs/aws-k8s#creating-a-cluster) or [Cluster Autoscaler AWS documentation](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#permissions) for details. | +| cluster-autoscaler.rbac.serviceAccount.name | string | `"cluster-autoscaler-sa"` | Name of the IAM Service Account with the [necessary permissions](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#permissions) | +| engine.additionalAnnotations | object | `nil` | Additional annotations to add to the Engine deployment | +| engine.additionalLabels | object | `{}` | Additional labels to add to Engine resources | +| engine.affinity | object | `{}` | [Affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) to apply for Engine pods. | +| engine.chunking | object | `` | chunking defines the size of audio chunks to process in seconds. Adjusting these values will affect both inference performance and accuracy of results. Please contact your Deepgram Account Representative if you want to adjust any of these values. | +| engine.chunking.speechToText.batch.maxDuration | float | `nil` | minDuration is the maximum audio duration for a STT chunk size for a batch request | +| engine.chunking.speechToText.batch.minDuration | float | `nil` | minDuration is the minimum audio duration for a STT chunk size for a batch request | +| engine.chunking.speechToText.streaming.maxDuration | float | `nil` | minDuration is the maximum audio duration for a STT chunk size for a streaming request | +| engine.chunking.speechToText.streaming.minDuration | float | `nil` | minDuration is the minimum audio duration for a STT chunk size for a streaming request | +| engine.chunking.speechToText.streaming.step | float | `1` | step defines how often to return interim results, in seconds. This value may be lowered to increase the frequency of interim results. However, this also causes a significant decrease in the number of concurrent streams supported by a single GPU. Please contact your Deepgram Account representative for more details. | +| engine.concurrencyLimit.activeRequests | int | `nil` | activeRequests limits the number of active requests handled by a single Engine container. If additional requests beyond the limit are sent, the API container forming the request will try a different Engine pod. If no Engine pods are able to accept the request, the API will return a 429 HTTP response to the client. The `nil` default means no limit will be set. | +| engine.features.streamingNer | bool | `false` | Enables format entity tags on streaming audio *if* a valid NER model is available. | +| engine.halfPrecision.state | string | `"auto"` | Engine will automatically enable half precision operations if your GPU supports them. You can explicitly enable or disable this behavior with the state parameter which supports `"enable"`, `"disabled"`, and `"auto"`. | +| engine.image.path | string | `"quay.io/deepgram/self-hosted-engine"` | path configures the image path to use for creating Engine containers. You may change this from the public Quay image path if you have imported Deepgram images into a private container registry. | +| engine.image.pullPolicy | string | `"IfNotPresent"` | pullPolicy configures how the Kubelet attempts to pull the Deepgram Engine image | +| engine.image.tag | string | `"release-250331"` | tag defines which Deepgram release to use for Engine containers | +| engine.livenessProbe | object | `` | Liveness probe customization for Engine pods. | +| engine.metricsServer | object | `` | metricsServer exposes an endpoint on each Engine container for reporting inference-specific system metrics. See https://developers.deepgram.com/docs/metrics-guide#deepgram-engine for more details. | +| engine.metricsServer.host | string | `"0.0.0.0"` | host is the IP address to listen on for metrics requests. You will want to listen on all interfaces to interact with other pods in the cluster. | +| engine.metricsServer.port | int | `9991` | port to listen on for metrics requests | +| engine.modelManager.models.add | list | `[]` | Links to your Deepgram models to automatically download into storage backing a persistent volume. **Automatic model management is currently supported for AWS EFS volumes only.** Insert each model link provided to you by your Deepgram Account Representative. | +| engine.modelManager.models.links | list | `[]` | Deprecated field to automatically download models. Functionality still supported, but migration to use `engine.modelManager.models.add` is strongly recommended. | +| engine.modelManager.models.remove | list | `[]` | If desiring to remove a model from storage (to reduce number of models loaded by Engine on startup), move a link from the `engine.modelManager.models.add` section to this section. You can also use a model name instead of the full link to designate for removal. **Automatic model management is currently supported for AWS EFS volumes only.** | +| engine.modelManager.volumes.aws.efs.enabled | bool | `false` | Whether to use an [AWS Elastic File Sytem](https://aws.amazon.com/efs/) to store Deepgram models for use by Engine containers. This option requires your cluster to be running in [AWS EKS](https://aws.amazon.com/eks/). | +| engine.modelManager.volumes.aws.efs.fileSystemId | string | `nil` | FileSystemId of existing AWS Elastic File System where Deepgram model files will be persisted. You can find it using the AWS CLI: ``` $ aws efs describe-file-systems --query "FileSystems[*].FileSystemId" ``` | +| engine.modelManager.volumes.aws.efs.forceDownload | bool | `false` | Whether to force a fresh download of all model links provided, even if models are already present in EFS. | +| engine.modelManager.volumes.aws.efs.namePrefix | string | `"dg-models"` | Name prefix for the resources associated with the model storage in AWS EFS. | +| engine.modelManager.volumes.customVolumeClaim.enabled | bool | `false` | You may manually create your own PersistentVolume and PersistentVolumeClaim to store and expose model files to the Deepgram Engine. Configure your storage beforehand, and enable here. Note: Make sure the PV and PVC accessMode are set to `readWriteMany` or `readOnlyMany` | +| engine.modelManager.volumes.customVolumeClaim.modelsDirectory | string | `"/"` | Name of the directory within your pre-configured PersistentVolume where the models are stored | +| engine.modelManager.volumes.customVolumeClaim.name | string | `nil` | Name of your pre-configured PersistentVolumeClaim | +| engine.modelManager.volumes.gcp.gpd.enabled | bool | `false` | Whether to use an [GKE Persistent Disks](https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes) to store Deepgram models for use by Engine containers. This option requires your cluster to be running in [GCP GKE](https://cloud.google.com/kubernetes-engine). See the GKE documentation on [using pre-existing persistent disks](https://cloud.google.com/kubernetes-engine/docs/how-to/persistent-volumes/preexisting-pd). | +| engine.modelManager.volumes.gcp.gpd.fsType | string | `"ext4"` | | +| engine.modelManager.volumes.gcp.gpd.namePrefix | string | `"dg-models"` | Name prefix for the resources associated with the model storage in GCP GPD. | +| engine.modelManager.volumes.gcp.gpd.storageCapacity | string | `"40G"` | The size of your pre-existing persistent disk. | +| engine.modelManager.volumes.gcp.gpd.storageClassName | string | `"standard-rwo"` | The storageClassName of the existing persistent disk. | +| engine.modelManager.volumes.gcp.gpd.volumeHandle | string | `""` | The identifier of your pre-existing persistent disk. The format is projects/{project_id}/zones/{zone_name}/disks/{disk_name} for Zonal persistent disks, or projects/{project_id}/regions/{region_name}/disks/{disk_name} for Regional persistent disks. | +| engine.namePrefix | string | `"deepgram-engine"` | namePrefix is the prefix to apply to the name of all K8s objects associated with the Deepgram Engine containers. | +| engine.readinessProbe | object | `` | Readiness probe customization for Engine pods. | +| engine.resources | object | `` | Configure resource limits per Engine container. See [Deepgram's documentation](https://developers.deepgram.com/docs/self-hosted-deployment-environments#engine) for more details. | +| engine.resources.limits.gpu | int | `1` | gpu maps to the nvidia.com/gpu resource parameter | +| engine.resources.requests.gpu | int | `1` | gpu maps to the nvidia.com/gpu resource parameter | +| engine.securityContext | object | `{}` | [Security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for API pods. | +| engine.server | object | `` | Configure Engine containers to listen for requests from API containers. | +| engine.server.host | string | `"0.0.0.0"` | host is the IP address to listen on for inference requests. You will want to listen on all interfaces to interact with other pods in the cluster. | +| engine.server.port | int | `8080` | port to listen on for inference requests | +| engine.serviceAccount.create | bool | `true` | Specifies whether to create a default service account for the Deepgram Engine Deployment. | +| engine.serviceAccount.name | string | `nil` | Allows providing a custom service account name for the Engine component. If left empty, the default service account name will be used. If specified, and `engine.serviceAccount.create = true`, this defines the name of the default service account. If specified, and `engine.serviceAccount.create = false`, this provides the name of a preconfigured service account you wish to attach to the Engine deployment. | +| engine.startupProbe | object | `` | The startupProbe combination of `periodSeconds` and `failureThreshold` allows time for the container to load all models and start listening for incoming requests. Model load time can be affected by hardware I/O speeds, as well as network speeds if you are using a network volume mount for the models. If you are hitting the failure threshold before models are finished loading, you may want to extend the startup probe. However, this will also extend the time it takes to detect a pod that can't establish a network connection to validate its license. | +| engine.startupProbe.failureThreshold | int | `60` | failureThreshold defines how many unsuccessful startup probe attempts are allowed before the container will be marked as Failed | +| engine.startupProbe.periodSeconds | int | `10` | periodSeconds defines how often to execute the probe. | +| engine.tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) to apply to Engine pods. | +| engine.updateStrategy.rollingUpdate.maxSurge | int | `1` | The maximum number of extra Engine pods that can be created during a rollingUpdate, relative to the number of replicas. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-surge) for more details. | +| engine.updateStrategy.rollingUpdate.maxUnavailable | int | `0` | The maximum number of Engine pods, relative to the number of replicas, that can go offline during a rolling update. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-unavailable) for more details. | +| global.additionalLabels | object | `{}` | Additional labels to add to all Deepgram resources | +| global.deepgramSecretRef | string | `nil` | Name of the pre-configured K8s Secret containing your Deepgram self-hosted API key. See chart docs for more details. | +| global.outstandingRequestGracePeriod | int | `1800` | When an API or Engine container is signaled to shutdown via Kubernetes sending a SIGTERM signal, the container will stop listening on its port, and no new requests will be routed to that container. However, the container will continue to run until all existing batch or streaming requests have completed, after which it will gracefully shut down. Batch requests should be finished within 10-15 minutes, but streaming requests can proceed indefinitely. outstandingRequestGracePeriod defines the period (in sec) after which Kubernetes will forcefully shutdown the container, terminating any outstanding connections. 1800 / 60 sec/min = 30 mins | +| global.pullSecretRef | string | `nil` | If using images from the Deepgram Quay image repositories, or another private registry to which your cluster doesn't have default access, you will need to provide a pre-configured K8s Secret with image repository credentials. See chart docs for more details. | +| gpu-operator | object | `` | Passthrough values for [NVIDIA GPU Operator Helm chart](https://github.com/NVIDIA/gpu-operator/blob/master/deployments/gpu-operator/values.yaml) You may use the NVIDIA GPU Operator to manage installation of NVIDIA drivers and the container toolkit on nodes with attached GPUs. | +| gpu-operator.driver.enabled | bool | `true` | Whether to install NVIDIA drivers on nodes where a NVIDIA GPU is detected. If your Kubernetes nodes run a base image that comes with NVIDIA drivers pre-configured, disable this option, but keep the parent `gpu-operator` and sibling `toolkit` options enabled. | +| gpu-operator.driver.version | string | `"550.54.15"` | NVIDIA driver version to install. | +| gpu-operator.enabled | bool | `true` | Whether to install the NVIDIA GPU Operator to manage driver and/or container toolkit installation. See the list of [supported Operating Systems](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/platform-support.html#supported-operating-systems-and-kubernetes-platforms) to verify compatibility with your cluster/nodes. Disable this option if your cluster/nodes are not compatible. If disabled, you will need to self-manage NVIDIA software installation on all nodes where you want to schedule Deepgram Engine pods. | +| gpu-operator.toolkit.enabled | bool | `true` | Whether to install NVIDIA drivers on nodes where a NVIDIA GPU is detected. | +| gpu-operator.toolkit.version | string | `"v1.15.0-ubi8"` | NVIDIA container toolkit to install. The default `ubuntu` image tag for the toolkit requires a dynamic runtime link to a version of GLIBC that may not be present on nodes running older Linux distribution releases, such as Ubuntu 22.04. Therefore, we specify the `ubi8` image, which statically links the GLIBC library and avoids this issue. | +| kube-prometheus-stack | object | `` | Passthrough values for [Prometheus k8s stack Helm chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack). Prometheus (and its adapter) should be configured when scaling.auto is enabled. You may choose to use the installation/configuration bundled in this Helm chart, or you may configure an existing Prometheus installation in your cluster to expose the needed values. See source Helm chart for explanation of available values. Default values provided in this chart are used to provide pod autoscaling for Deepgram pods. | +| kube-prometheus-stack.includeDependency | bool | `nil` | Normally, this chart will be installed if `scaling.auto.enabled` is true. However, if you wish to manage the Prometheus adapter in your cluster on your own and not as part of the Deepgram Helm chart, you can force it to not be installed by setting this to `false`. | +| licenseProxy | object | `` | Configuration options for the optional [Deepgram License Proxy](https://developers.deepgram.com/docs/license-proxy). | +| licenseProxy.additionalAnnotations | object | `nil` | Additional annotations to add to the LicenseProxy deployment | +| licenseProxy.additionalLabels | object | `{}` | Additional labels to add to License Proxy resources | +| licenseProxy.affinity | object | `{}` | [Affinity and anti-affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#affinity-and-anti-affinity) to apply for License Proxy pods. | +| licenseProxy.deploySecondReplica | bool | `false` | If the License Proxy is deployed, one replica should be sufficient to support many API/Engine pods. Highly available environments may wish to deploy a second replica to ensure uptime, which can be toggled with this option. | +| licenseProxy.enabled | bool | `false` | The License Proxy is optional, but highly recommended to be deployed in production to enable highly available environments. | +| licenseProxy.image.path | string | `"quay.io/deepgram/self-hosted-license-proxy"` | path configures the image path to use for creating License Proxy containers. You may change this from the public Quay image path if you have imported Deepgram images into a private container registry. | +| licenseProxy.image.pullPolicy | string | `"IfNotPresent"` | pullPolicy configures how the Kubelet attempts to pull the Deepgram License Proxy image | +| licenseProxy.image.tag | string | `"release-250331"` | tag defines which Deepgram release to use for License Proxy containers | +| licenseProxy.keepUpstreamServerAsBackup | bool | `true` | Even with a License Proxy deployed, API and Engine pods can be configured to keep the upstream `license.deepgram.com` license server as a fallback licensing option if the License Proxy is unavailable. Disable this option if you are restricting API/Engine Pod network access for security reasons, and only the License Proxy should send egress traffic to the upstream license server. | +| licenseProxy.livenessProbe | object | `` | Liveness probe customization for Proxy pods. | +| licenseProxy.namePrefix | string | `"deepgram-license-proxy"` | namePrefix is the prefix to apply to the name of all K8s objects associated with the Deepgram License Proxy containers. | +| licenseProxy.readinessProbe | object | `` | Readiness probe customization for License Proxy pods. | +| licenseProxy.resources | object | `` | Configure resource limits per License Proxy container. See [Deepgram's documentation](https://developers.deepgram.com/docs/license-proxy#system-requirements) for more details. | +| licenseProxy.securityContext | object | `{}` | [Security context](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) for API pods. | +| licenseProxy.server | object | `` | Configure how the license proxy will listen for licensing requests. | +| licenseProxy.server.baseUrl | string | `"/"` | baseUrl is the prefix for incoming license verification requests. | +| licenseProxy.server.host | string | `"0.0.0.0"` | host is the IP address to listen on. You will want to listen on all interfaces to interact with other pods in the cluster. | +| licenseProxy.server.port | int | `8443` | port to listen on. | +| licenseProxy.server.statusPort | int | `8080` | statusPort is the port to listen on for the status/health endpoint. | +| licenseProxy.serviceAccount.create | bool | `true` | Specifies whether to create a default service account for the Deepgram License Proxy Deployment. | +| licenseProxy.serviceAccount.name | string | `nil` | Allows providing a custom service account name for the LicenseProxy component. If left empty, the default service account name will be used. If specified, and `licenseProxy.serviceAccount.create = true`, this defines the name of the default service account. If specified, and `licenseProxy.serviceAccount.create = false`, this provides the name of a preconfigured service account you wish to attach to the License Proxy deployment. | +| licenseProxy.tolerations | list | `[]` | [Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) to apply to License Proxy pods. | +| licenseProxy.updateStrategy.rollingUpdate | object | `` | For the LicenseProxy, we only expose maxSurge and not maxUnavailable. This is to avoid accidentally having all LicenseProxy nodes go offline during upgrades, which could impact the entire cluster's connection to the Deepgram License Server. | +| licenseProxy.updateStrategy.rollingUpdate.maxSurge | int | `1` | The maximum number of extra License Proxy pods that can be created during a rollingUpdate, relative to the number of replicas. See the [Kubernetes documentation](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#max-surge) for more details. | +| prometheus-adapter | object | `` | Passthrough values for [Prometheus Adapter Helm chart](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-adapter). Prometheus, and its adapter here, should be configured when scaling.auto is enabled. You may choose to use the installation/configuration bundled in this Helm chart, or you may configure an existing Prometheus installation in your cluster to expose the needed values. See source Helm chart for explanation of available values. Default values provided in this chart are used to provide pod autoscaling for Deepgram pods. | +| prometheus-adapter.includeDependency | string | `nil` | Normally, this chart will be installed if `scaling.auto.enabled` is true. However, if you wish to manage the Prometheus adapter in your cluster on your own and not as part of the Deepgram Helm chart, you can force it to not be installed by setting this to `false`. | +| scaling | object | `` | Configuration options for horizontal scaling of Deepgram services. Only one of `static` and `auto` options can be enabled. | +| scaling.auto | object | `` | Enable pod autoscaling based on system load/traffic. | +| scaling.auto.api.metrics.custom | list | `nil` | If you have custom metrics you would like to scale with, you may add them here. See the [k8s docs](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) for how to structure a list of metrics | +| scaling.auto.api.metrics.engineToApiRatio | int | `4` | Scale the API deployment to this Engine-to-Api pod ratio | +| scaling.auto.engine.behavior | object | "*See values.yaml file for default*" | [Configurable scaling behavior](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/#configurable-scaling-behavior) | +| scaling.auto.engine.maxReplicas | int | `10` | Maximum number of Engine replicas. | +| scaling.auto.engine.metrics.custom | list | `[]` | If you have custom metrics you would like to scale with, you may add them here. See the [k8s docs](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) for how to structure a list of metrics | +| scaling.auto.engine.metrics.requestCapacityRatio | string | `nil` | If `engine.concurrencyLimit.activeRequests` is set, this variable will define the ratio of current active requests to maximum active requests at which the Engine pods will scale. Setting this value too close to 1.0 may lead to a situation where the cluster is at max capacity and rejects incoming requests. Setting the ratio too close to 0.0 will over-optimistically scale your cluster and increase compute costs unnecessarily. | +| scaling.auto.engine.metrics.speechToText.batch.requestsPerPod | int | `nil` | Scale the Engine pods based on a static desired number of speech-to-text batch requests per pod | +| scaling.auto.engine.metrics.speechToText.streaming.requestsPerPod | int | `nil` | Scale the Engine pods based on a static desired number of speech-to-text streaming requests per pod | +| scaling.auto.engine.metrics.textToSpeech.batch.requestsPerPod | int | `nil` | Scale the Engine pods based on a static desired number of text-to-speech batch requests per pod | +| scaling.auto.engine.minReplicas | int | `1` | Minimum number of Engine replicas. | +| scaling.replicas | object | `` | Number of replicas to set during initial installation. | + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Deepgram Self-Hosted | | | diff --git a/backend/charts/deepgram-self-hosted/nova-3/README.md.gotmpl b/backend/charts/deepgram-self-hosted/nova-3/README.md.gotmpl new file mode 100644 index 000000000..afc6dfedd --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/README.md.gotmpl @@ -0,0 +1,168 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} + +{{ template "chart.versionBadge" . }}{{ template "chart.typeBadge" . }}{{ template "chart.appVersionBadge" . }}[![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/deepgram-self-hosted)](https://artifacthub.io/packages/search?repo=deepgram-self-hosted) + +{{ template "chart.description" . }} + +{{ template "chart.homepageLine" . }} + +**Deepgram Self-Hosted Kubernetes Guides:** + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +## Using the Chart + +### Get Repository Info + +```bash +helm repo add deepgram https://deepgram.github.io/self-hosted-resources +helm repo update +``` + +### Installing the Chart + +The Deepgram self-hosted chart requires Helm 3.7+ in order to install successfully. Please check your helm release before installation. + +You will need to provide your [self-service Deepgram licensing and credentials](https://developers.deepgram.com/docs/self-hosted-self-service-tutorial) information. See `global.deepgramSecretRef` and `global.pullSecretRef` in the [Values section](#values) for more details, and the [Deepgram Self-Hosted Kubernetes Guides](https://developers.deepgram.com/docs/kubernetes) for instructions on how to create these secrets. + +You may also override any default configuration values. See [the Values section](#values) for a list of available options, and the [samples directory](./samples) for examples of a standard installation. + +``` +helm install -f my-values.yaml [RELEASE_NAME] deepgram/deepgram-self-hosted --atomic --timeout 45m +``` + +### Upgrade and Rollback Strategies + +To upgrade the Deepgram components to a new version, follow these steps: + +1. Update the various `image.tag` values in the `values.yaml` file to the desired version. + +2. Run the Helm upgrade command: + + ```bash + helm upgrade -f my-values.yaml [RELEASE_NAME] deepgram/deepgram-self-hosted --atomic --timeout 60m + ``` + +If you encounter any issues during the upgrade process, you can perform a rollback to the previous version: + +```bash +helm rollback deepgram +``` + +Before upgrading, ensure that you have reviewed the release notes and any migration guides provided by Deepgram for the specific version you are upgrading to. + +### Uninstalling the Chart + +```bash +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +## Changelog + +See the [chart CHANGELOG](./CHANGELOG.md) for a list of relevant changes for each version of the Helm chart. + +For more details on changes to the underlying Deepgram resources, such as the container images or available models, see the [official Deepgram changelog](https://deepgram.com/changelog) ([RSS feed](https://deepgram.com/changelog.xml)). + +## Chart Configuration + +### Persistent Storage Options + +The Deepgram Helm chart supports different persistent storage options for storing Deepgram models and data. The available options include: + +- AWS Elastic File System (EFS) +- Google Cloud Persistent Disk (GPD) +- Custom PersistentVolumeClaim (PVC) + +To configure a specific storage option, see the `engine.modelManager.volumes` [configuration values](#values). Make sure to provide the necessary configuration values for the selected storage option, such as the EFS file system ID or the GPD disk type and size. + +For detailed instructions on setting up and configuring each storage option, refer to the [Deepgram self-hosted guides](https://developers.deepgram.com/docs/kubernetes) and the respective cloud provider's documentation. + +### Autoscaling + +Autoscaling your cluster's capacity to meet incoming traffic demands involves both node autoscaling and pod autoscaling. Node autoscaling for supported cloud providers is setup by default when using this Helm chart and creating your cluster with the [Deepgram self-hosted guides](https://developers.deepgram.com/docs/kubernetes). Pod autoscaling can be enabled via the `scaling.auto.enabled` configuration option in this chart. + +#### Engine + +The Engine component is the core of the Deepgram self-hosted platform, responsible for performing inference using your deployed models. Autoscaling increases the number of Engine replicas to maintain consistent performance for incoming traffic. + +There are currently two primary ways to scale the Engine component: scaling with a hard request limit per Engine Pod, or scaling with a soft request limit per Engine pod. + +To set a hard limit on which to scale, configure `engine.concurrencyLimit.activeRequests` and `scaling.auto.engine.metrics.requestCapacityRatio`. The `activeRequests` parameter will set a hard limit of how many requests any given Engine pod will accept, and the `requestCapacityRatio` will govern scaling the Engine deployment when a certain percentage of "available request slots" is filled. For example, a requestCapacityRatio of `0.8` will scale the Engine deployment when the current number of active requests is >=80% of the active request concurrency limit. If the cluster is not able to scale in time and current active requests hits 100% of the preset limit, additional client requests to the API will return a `429 Too Many Requests` HTTP response to clients. This hard limit means that if a request is accepted for inference, it will have consistent performance, as the cluster will refuse surplus requests that could overload the cluster and degrade performance, at the expense of possibly rejecting some incoming requests if capacity does not scale in time. + +To set a soft limit on which to scale, configure `scaling.auto.engine.metrics.{speechToText,textToSpeech}.{batch,streaming}.requestsPerPod`, depending on the primary traffic source for your environment. The cluster will attempt to scale to meet this target for number of requests per Engine pod, but will not reject extra requests with a `429 Too Many Request` HTTP response like the hard limit will. If the number of extra requests increases faster than the cluster can scale additional capacity, all incoming requests will still be accepted, but the performance of individual requests may degrade. + +> [!NOTE] +> Deepgram recommends provisioning separate environments for batch speech-to-text, streaming speech-to-text, and text-to-speech workloads because typical latency and throughput tradeoffs are different for each of those use cases. + +There is also a `scaling.auto.engine.metrics.custom` configuration value available to define your own custom scaling metric, if needed. + +#### API + +The API component is responsible for accepting incoming requests and forming responses, delegating inference work to the Deepgram Engine as needed. A single API pod can typically handle delegating requests to multiple Engine pods, so it is more compute efficient to deploy fewer API pods relative to the number of Engine pods. The `scaling.auto.api.metrics.engineToApiRatio` configuration value defines the ratio between Engine to API pods. The default value is appropriate for most deployments. + +There is also a `scaling.auto.api.metrics.custom` configuration value available to define your own custom scaling metric, if needed. + +#### License Proxy + +The [License Proxy](https://developers.deepgram.com/docs/license-proxy) is intended to be deployed as a fixed-scale deployment the proxies all licensing requests from your environment. It should not be upscaled with the traffic demands of your environment. + +This chart deploys one License Proxy Pod per environment by default. If you wish to deploy a second License Proxy Pod for redundancy, set `licenseProxy.deploySecondReplica` to `true`. + +### RBAC Configuration + +Role-Based Access Control (RBAC) is used to control access to Kubernetes resources based on the roles and permissions assigned to users or service accounts. The Deepgram Helm chart includes default RBAC roles and bindings for the API, Engine, and License Proxy components. + +To use custom RBAC roles and bindings based on your specific security requirements, you can individually specify pre-existing ServiceAccounts to bind to each deployment by specifying the following options in `values.yaml`: + +``` +{api|engine|licenseProxy}.serviceAccount.create=false +{api|engine|licenseProxy}.serviceAccount.name= +``` + +Make sure to review and adjust the RBAC configuration according to the principle of least privilege, granting only the necessary permissions for each component. + +### Secret Management + +The Deepgram Helm chart takes references to two existing secrets - one containing your distribution credentials to pull container images from Deepgram's image repository, and one containing your Deepgram self-hosted API key. + +Consult the [official Kubernetes documentation](https://kubernetes.io/docs/concepts/configuration/secret/) for best practices on configuring Secrets for use in your cluster. + +## Getting Help + +See the [Getting Help](../../README.md#getting-help) section in the root of this repository for a list of resources to help you troubleshoot and resolve issues. + +### Troubleshooting + +If you encounter issues while deploying or using Deepgram, consider the following troubleshooting steps: + +1. Check the pod status and logs: + - Use `kubectl get pods` to check the status of the Deepgram pods. + - Use `kubectl logs ` to view the logs of a specific pod. + +2. Verify resource availability: + - Ensure that the cluster has sufficient CPU, memory, and storage resources to accommodate the Deepgram components. + - Check for any resource constraints or limits imposed by the namespace or the cluster. + +3. Review the Kubernetes events: + - Use `kubectl get events` to view any events or errors related to the Deepgram deployment. + +4. Check the network connectivity: + - Verify that the Deepgram components can communicate with each other and with the Deepgram license server (license.deepgram.com). + - Check the network policies and firewall rules to ensure that the necessary ports and protocols are allowed. + +5. Collect diagnostic information: + - Gather relevant logs and metrics. + - Export your existing Helm chart values: + ```bash + helm get values [RELEASE_NAME] > my-deployed-values.yaml + ``` + - Provide the collected diagnostic information to Deepgram for assistance. + +{{ template "chart.valuesSection" . }} + +{{ template "chart.maintainersSection" . }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/.helmignore b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/Chart.yaml new file mode 100644 index 000000000..a8cfb9c52 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/Chart.yaml @@ -0,0 +1,13 @@ +apiVersion: v2 +appVersion: 1.32.0 +description: Scales Kubernetes worker nodes within autoscaling groups. +home: https://github.com/kubernetes/autoscaler +icon: https://github.com/kubernetes/kubernetes/raw/master/logo/logo.png +maintainers: +- email: guyjtempleton@googlemail.com + name: gjtempleton +name: cluster-autoscaler +sources: +- https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler +type: application +version: 9.46.3 diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md new file mode 100644 index 000000000..5ccbdd3ff --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md @@ -0,0 +1,528 @@ +# cluster-autoscaler + +Scales Kubernetes worker nodes within autoscaling groups. + +## TL;DR + +```console +$ helm repo add autoscaler https://kubernetes.github.io/autoscaler + +# Method 1 - Using Autodiscovery +$ helm install my-release autoscaler/cluster-autoscaler \ + --set 'autoDiscovery.clusterName'= + +# Method 2 - Specifying groups manually +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +## Introduction + +This chart bootstraps a cluster-autoscaler deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Helm 3+ +- Kubernetes 1.8+ + - [Older versions](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#releases) may work by overriding the `image`. Cluster autoscaler internally simulates the scheduler and bugs between mismatched versions may be subtle. +- Azure AKS specific Prerequisites: + - Kubernetes 1.10+ with RBAC-enabled. + +## Previous Helm Chart + +The previous `cluster-autoscaler` Helm chart hosted at [helm/charts](https://github.com/helm/charts) has been moved to this repository in accordance with the [Deprecation timeline](https://github.com/helm/charts#deprecation-timeline). Note that a few things have changed between this version and the old version: + +- This repository **only** supports Helm chart installations using Helm 3+ since the `apiVersion` on the charts has been marked as `v2`. +- Previous versions of the Helm chart have not been migrated + +## Migration from 1.X to 9.X+ versions of this Chart + +**TL;DR:** +You should choose to use versions >=9.0.0 of the `cluster-autoscaler` chart published from this repository; previous versions, and the `cluster-autoscaler-chart` with versioning 1.X.X published from this repository are deprecated. + +
+ Previous versions of this chart - further details +On initial migration of this chart from the `helm/charts` repository this chart was renamed from `cluster-autoscaler` to `cluster-autoscaler-chart` due to technical limitations. This affected all `1.X` releases of the chart, version 2.0.0 of this chart exists only to mark the [`cluster-autoscaler-chart` chart](https://artifacthub.io/packages/helm/cluster-autoscaler/cluster-autoscaler-chart) as deprecated. + +Releases of the chart from `9.0.0` onwards return the naming of the chart to `cluster-autoscaler` and return to following the versioning established by the chart's previous location at . + +To migrate from a 1.X release of the chart to a `9.0.0` or later release, you should first uninstall your `1.X` install of the `cluster-autoscaler-chart` chart, before performing the installation of the new `cluster-autoscaler` chart. +
+ +## Migration from 9.0 to 9.1 + +Starting from `9.1.0` the `envFromConfigMap` value is expected to contain the name of a ConfigMap that is used as ref for `envFrom`, similar to `envFromSecret`. If you want to keep the previous behaviour of `envFromConfigMap` you must rename it to `extraEnvConfigMaps`. + +## Installing the Chart + +**By default, no deployment is created and nothing will autoscale**. + +You must provide some minimal configuration, either to specify instance groups or enable auto-discovery. It is not recommended to do both. + +Either: + +- Set `autoDiscovery.clusterName` and provide additional autodiscovery options if necessary **or** +- Set static node group configurations for one or more node groups (using `autoscalingGroups` or `autoscalingGroupsnamePrefix`). + +To create a valid configuration, follow instructions for your cloud provider: + +- [AWS](#aws---using-auto-discovery-of-tagged-instance-groups) +- [GCE](#gce) +- [Azure](#azure) +- [OpenStack Magnum](#openstack-magnum) +- [Cluster API](#cluster-api) +- [Exoscale](#exoscale) +- [Hetzner Cloud](#hetzner-cloud) +- [Civo](#civo) + +### Templating the autoDiscovery.clusterName + +The cluster name can be templated in the `autoDiscovery.clusterName` variable. This is useful when the cluster name is dynamically generated based on other values coming from external systems like Argo CD or Flux. This also allows you to use global Helm values to set the cluster name, e.g., `autoDiscovery.clusterName=\{\{ .Values.global.clusterName }}`, so that you don't need to set it in more than 1 location in the values file. + +### AWS - Using auto-discovery of tagged instance groups + +Auto-discovery finds ASGs tags as below and automatically manages them based on the min and max size specified in the ASG. `cloudProvider=aws` only. + +- Tag the ASGs with keys to match `.Values.autoDiscovery.tags`, by default: `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/` +- Verify the [IAM Permissions](#aws---iam) +- Set `autoDiscovery.clusterName=` +- Set `awsRegion=` +- Set (option) `awsAccessKeyID=` and `awsSecretAccessKey=` if you want to [use AWS credentials directly instead of an instance role](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials) + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= +``` + +Alternatively with your own AWS credentials + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= \ + --set awsAccessKeyID= \ + --set awsSecretAccessKey= +``` + +#### Specifying groups manually + +Without autodiscovery, specify an array of elements each containing ASG name, min size, max size. The sizes specified here will be applied to the ASG, assuming IAM permissions are correctly configured. + +- Verify the [IAM Permissions](#aws---iam) +- Either provide a yaml file setting `autoscalingGroups` (see values.yaml) or use `--set` e.g.: + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +#### Auto-discovery + +For auto-discovery of instances to work, they must be tagged with the keys in `.Values.autoDiscovery.tags`, which by default are `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/`. + +The value of the tag does not matter, only the key. + +An example kops spec excerpt: + +```yaml +apiVersion: kops/v1alpha2 +kind: Cluster +metadata: + name: my.cluster.internal +spec: + additionalPolicies: + node: | + [ + {"Effect":"Allow","Action":["autoscaling:DescribeAutoScalingGroups","autoscaling:DescribeAutoScalingInstances","autoscaling:DescribeLaunchConfigurations","autoscaling:DescribeTags","autoscaling:SetDesiredCapacity","autoscaling:TerminateInstanceInAutoScalingGroup"],"Resource":"*"} + ] + ... +--- +apiVersion: kops/v1alpha2 +kind: InstanceGroup +metadata: + labels: + kops.k8s.io/cluster: my.cluster.internal + name: my-instances +spec: + cloudLabels: + k8s.io/cluster-autoscaler/enabled: "" + k8s.io/cluster-autoscaler/my.cluster.internal: "" + image: kops.io/k8s-1.8-debian-jessie-amd64-hvm-ebs-2018-01-14 + machineType: r4.large + maxSize: 4 + minSize: 0 +``` + +In this example you would need to `--set autoDiscovery.clusterName=my.cluster.internal` when installing. + +It is not recommended to try to mix this with setting `autoscalingGroups`. + +See [autoscaler AWS documentation](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup) for a more discussion of the setup. + +### GCE + +The following parameters are required: + +- `autoDiscovery.clusterName=any-name` +- `cloud-provider=gce` +- `autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefix[0].minSize=1` + +To use Managed Instance Group (MIG) auto-discovery, provide a YAML file setting `autoscalingGroupsnamePrefix` (see values.yaml) or use `--set` when installing the Chart - e.g. + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefi[0].minSize=1" \ + --set autoDiscovery.clusterName= \ + --set cloudProvider=gce +``` + +Note that `your-ig-prefix` should be a _prefix_ matching one or more MIGs, and _not_ the full name of the MIG. For example, to match multiple instance groups - `k8s-node-group-a-standard`, `k8s-node-group-b-gpu`, you would use a prefix of `k8s-node-group-`. + +In the event you want to explicitly specify MIGs instead of using auto-discovery, set members of the `autoscalingGroups` array directly - e.g. + +``` +# where 'n' is the index, starting at 0 +--set autoscalingGroups[n].name=https://content.googleapis.com/compute/v1/projects/$PROJECTID/zones/$ZONENAME/instanceGroups/$FULL-MIG-NAME,autoscalingGroups[n].maxSize=$MAXSIZE,autoscalingGroups[n].minSize=$MINSIZE +``` + +### Azure + +The following parameters are required: + +- `cloudProvider=azure` +- `autoscalingGroups[0].name=your-vmss,autoscalingGroups[0].maxSize=10,autoscalingGroups[0].minSize=1` +- `azureClientID: "your-service-principal-app-id"` +- `azureClientSecret: "your-service-principal-client-secret"` +- `azureSubscriptionID: "your-azure-subscription-id"` +- `azureTenantID: "your-azure-tenant-id"` +- `azureResourceGroup: "your-aks-cluster-resource-group-name"` +- `azureVMType: "vmss"` + +### OpenStack Magnum + +`cloudProvider: magnum` must be set, and then one of + +- `magnumClusterName=` and `autoscalingGroups` with the names of node groups and min/max node counts +- or `autoDiscovery.clusterName=` with one or more `autoDiscovery.roles`. + +Additionally, `cloudConfigPath: "/etc/kubernetes/cloud-config"` must be set as this should be the location of the cloud-config file on the host. + +Example values files can be found [here](../../cluster-autoscaler/cloudprovider/magnum/examples). + +Install the chart with + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f myvalues.yaml +``` + +### Cluster-API + +`cloudProvider: clusterapi` must be set, and then one or more of + +- `autoDiscovery.clusterName` +- or `autoDiscovery.namespace` +- or `autoDiscovery.labels` + +See [here](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery) for more details. + +Additional config parameters available, see the `values.yaml` for more details + +- `clusterAPIMode` +- `clusterAPIKubeconfigSecret` +- `clusterAPIWorkloadKubeconfigPath` +- `clusterAPICloudConfigPath` + +### Exoscale + +Create a `values.yaml` file with the following content: +```yaml +cloudProvider: exoscale +autoDiscovery: + clusterName: cluster.local # this value is not used, but must be set +``` + +Optionally, you may specify the minimum and maximum size of a particular nodepool by adding the following to the `values.yaml` file: +```yaml +autoscalingGroups: + - name: your-nodepool-name + maxSize: 10 + minSize: 1 +``` + +Create an Exoscale API key with appropriate permissions as described in [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md). +A secret of name `-exoscale-cluster-autoscaler` needs to be created, containing the api key and secret, as well as the zone. + +```console +$ kubectl create secret generic my-release-exoscale-cluster-autoscaler \ + --from-literal=api-key="EXOxxxxxxxxxxxxxxxxxxxxxxxx" \ + --from-literal=api-secret="xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --from-literal=api-zone="ch-gva-2" +``` + +After creating the secret, the chart may be installed: + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f values.yaml +``` + +Read [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md) for further information on the setup without helm. + +### Hetzner Cloud + +The following parameters are required: + +- `cloudProvider=hetzner` +- `extraEnv.HCLOUD_TOKEN=...` +- `autoscalingGroups=...` + +Each autoscaling group requires an additional `instanceType` and `region` key to be set. + +Read [cluster-autoscaler/cloudprovider/hetzner/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/hetzner/README.md) for further information on the setup without helm. + +### Civo + +The following parameters are required: + +- `cloudProvider=civo` +- `autoscalingGroups=...` + +When installing the helm chart to the namespace `kube-system`, you can set `secretKeyRefNameOverride` to `civo-api-access`. +Otherwise specify the following parameters: + +- `civoApiUrl=https://api.civo.com` +- `civoApiKey=...` +- `civoClusterID=...` +- `civoRegion=...` + +Read [cluster-autoscaler/cloudprovider/civo/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/civo/README.md) for further information on the setup without helm. + +## Uninstalling the Chart + +To uninstall `my-release`: + +```console +$ helm uninstall my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +> **Tip**: List all releases using `helm list` or start clean with `helm uninstall my-release` + +## Additional Configuration + +### AWS - IAM + +The worker running the cluster autoscaler will need access to certain resources and actions depending on the version you run and your configuration of it. + +For the up-to-date IAM permissions required, please see the [cluster autoscaler's AWS Cloudprovider Readme](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#iam-policy) and switch to the tag of the cluster autoscaler image you are using. + +### AWS - IAM Roles for Service Accounts (IRSA) + +For Kubernetes clusters that use Amazon EKS, the service account can be configured with an IAM role using [IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to avoid needing to grant access to the worker nodes for AWS resources. + +In order to accomplish this, you will first need to create a new IAM role with the above mentions policies. Take care in [configuring the trust relationship](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html#iam-role-configuration) to restrict access just to the service account used by cluster autoscaler. + +Once you have the IAM role configured, you would then need to `--set rbac.serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789012:role/MyRoleName` when installing. + +### Azure - Using azure workload identity + +You can use the project [Azure workload identity](https://github.com/Azure/azure-workload-identity), to automatically configure the correct setup for your pods to used federated identity with Azure. + +You can also set the correct settings yourself instead of relying on this project. + +For example the following configuration will configure the Autoscaler to use your federated identity: + +```yaml +azureUseWorkloadIdentityExtension: true +extraEnv: + AZURE_CLIENT_ID: USER ASSIGNED IDENTITY CLIENT ID + AZURE_TENANT_ID: USER ASSIGNED IDENTITY TENANT ID + AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/tokens/azure-identity-token + AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/ +extraVolumes: +- name: azure-identity-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + audience: api://AzureADTokenExchange + expirationSeconds: 3600 + path: azure-identity-token +extraVolumeMounts: +- mountPath: /var/run/secrets/tokens + name: azure-identity-token + readOnly: true +``` + +### Custom arguments + +You can use the `customArgs` value to give any argument to cluster autoscaler command. + +Typical use case is to give an environment variable as an argument which will be interpolated at execution time. + +This is helpful when you need to inject values from configmap or secret. + +## Troubleshooting + +The chart will succeed even if the container arguments are incorrect. A few minutes after starting `kubectl logs -l "app=aws-cluster-autoscaler" --tail=50` should loop through something like + +``` +polling_autoscaler.go:111] Poll finished +static_autoscaler.go:97] Starting main loop +utils.go:435] No pod using affinity / antiaffinity found in cluster, disabling affinity predicate for this loop +static_autoscaler.go:230] Filtering out schedulables +``` + +If not, find a pod that the deployment created and `describe` it, paying close attention to the arguments under `Command`. e.g.: + +``` +Containers: + cluster-autoscaler: + Command: + ./cluster-autoscaler + --cloud-provider=aws +# if specifying ASGs manually + --nodes=1:10:your-scaling-group-name +# if using autodiscovery + --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/ + --v=4 +``` + +### PodSecurityPolicy + +Though enough for the majority of installations, the default PodSecurityPolicy _could_ be too restrictive depending on the specifics of your release. Please make sure to check that the template fits with any customizations made or disable it by setting `rbac.pspEnabled` to `false`. + +### VerticalPodAutoscaler + +The CA Helm Chart can install a [`VerticalPodAutoscaler`](https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/README.md) object from Chart version `9.27.0` +onwards for the Cluster Autoscaler Deployment to scale the CA as appropriate, but for that, we +need to install the VPA to the cluster separately. A VPA can help minimize wasted resources +when usage spikes periodically or remediate containers that are being OOMKilled. + +The following example snippet can be used to install VPA that allows scaling down from the default recommendations of the deployment template: + +```yaml +vpa: + enabled: true + containerPolicy: + minAllowed: + cpu: 20m + memory: 50Mi +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| additionalLabels | object | `{}` | Labels to add to each object of the chart. | +| affinity | object | `{}` | Affinity for pod assignment | +| autoDiscovery.clusterName | string | `nil` | Enable autodiscovery for `cloudProvider=aws`, for groups matching `autoDiscovery.tags`. autoDiscovery.clusterName -- Enable autodiscovery for `cloudProvider=azure`, using tags defined in https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/azure/README.md#auto-discovery-setup. Enable autodiscovery for `cloudProvider=clusterapi`, for groups matching `autoDiscovery.labels`. Enable autodiscovery for `cloudProvider=gce`, but no MIG tagging required. Enable autodiscovery for `cloudProvider=magnum`, for groups matching `autoDiscovery.roles`. | +| autoDiscovery.labels | list | `[]` | Cluster-API labels to match https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery | +| autoDiscovery.namespace | string | `nil` | Enable autodiscovery via cluster namespace for for `cloudProvider=clusterapi` | +| autoDiscovery.roles | list | `["worker"]` | Magnum node group roles to match. | +| autoDiscovery.tags | list | `["k8s.io/cluster-autoscaler/enabled","k8s.io/cluster-autoscaler/{{ .Values.autoDiscovery.clusterName }}"]` | ASG tags to match, run through `tpl`. | +| autoscalingGroups | list | `[]` | For AWS, Azure AKS, Exoscale or Magnum. At least one element is required if not using `autoDiscovery`. For example:
 - name: asg1
maxSize: 2
minSize: 1
For Hetzner Cloud, the `instanceType` and `region` keys are also required.
 - name: mypool
maxSize: 2
minSize: 1
instanceType: CPX21
region: FSN1
| +| autoscalingGroupsnamePrefix | list | `[]` | For GCE. At least one element is required if not using `autoDiscovery`. For example:
 - name: ig01
maxSize: 10
minSize: 0
| +| awsAccessKeyID | string | `""` | AWS access key ID ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) | +| awsRegion | string | `"us-east-1"` | AWS region (required if `cloudProvider=aws`) | +| awsSecretAccessKey | string | `""` | AWS access secret key ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) | +| azureClientID | string | `""` | Service Principal ClientID with contributor permission to Cluster and Node ResourceGroup. Required if `cloudProvider=azure` | +| azureClientSecret | string | `""` | Service Principal ClientSecret with contributor permission to Cluster and Node ResourceGroup. Required if `cloudProvider=azure` | +| azureEnableForceDelete | bool | `false` | Whether to force delete VMs or VMSS instances when scaling down. | +| azureResourceGroup | string | `""` | Azure resource group that the cluster is located. Required if `cloudProvider=azure` | +| azureSubscriptionID | string | `""` | Azure subscription where the resources are located. Required if `cloudProvider=azure` | +| azureTenantID | string | `""` | Azure tenant where the resources are located. Required if `cloudProvider=azure` | +| azureUseManagedIdentityExtension | bool | `false` | Whether to use Azure's managed identity extension for credentials. If using MSI, ensure subscription ID, resource group, and azure AKS cluster name are set. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. | +| azureUseWorkloadIdentityExtension | bool | `false` | Whether to use Azure's workload identity extension for credentials. See the project here: https://github.com/Azure/azure-workload-identity for more details. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. | +| azureUserAssignedIdentityID | string | `""` | When vmss has multiple user assigned identity assigned, azureUserAssignedIdentityID specifies which identity to be used | +| azureVMType | string | `"vmss"` | Azure VM type. | +| civoApiKey | string | `""` | API key for the Civo API. Required if `cloudProvider=civo` | +| civoApiUrl | string | `"https://api.civo.com"` | URL for the Civo API. Required if `cloudProvider=civo` | +| civoClusterID | string | `""` | Cluster ID for the Civo cluster. Required if `cloudProvider=civo` | +| civoRegion | string | `""` | Region for the Civo cluster. Required if `cloudProvider=civo` | +| cloudConfigPath | string | `""` | Configuration file for cloud provider. | +| cloudProvider | string | `"aws"` | The cloud provider where the autoscaler runs. Currently only `gce`, `aws`, `azure`, `magnum`, `clusterapi` and `civo` are supported. `aws` supported for AWS. `gce` for GCE. `azure` for Azure AKS. `magnum` for OpenStack Magnum, `clusterapi` for Cluster API. `civo` for Civo Cloud. | +| clusterAPICloudConfigPath | string | `"/etc/kubernetes/mgmt-kubeconfig"` | Path to kubeconfig for connecting to Cluster API Management Cluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or incluster-kubeconfig` | +| clusterAPIConfigMapsNamespace | string | `""` | Namespace on the workload cluster to store Leader election and status configmaps | +| clusterAPIKubeconfigSecret | string | `""` | Secret containing kubeconfig for connecting to Cluster API managed workloadcluster Required if `cloudProvider=clusterapi` and `clusterAPIMode=kubeconfig-kubeconfig,kubeconfig-incluster or incluster-kubeconfig` | +| clusterAPIMode | string | `"incluster-incluster"` | Cluster API mode, see https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#connecting-cluster-autoscaler-to-cluster-api-management-and-workload-clusters Syntax: workloadClusterMode-ManagementClusterMode for `kubeconfig-kubeconfig`, `incluster-kubeconfig` and `single-kubeconfig` you always must mount the external kubeconfig using either `extraVolumeSecrets` or `extraMounts` and `extraVolumes` if you dont set `clusterAPIKubeconfigSecret`and thus use an in-cluster config or want to use a non capi generated kubeconfig you must do so for the workload kubeconfig as well | +| clusterAPIWorkloadKubeconfigPath | string | `"/etc/kubernetes/value"` | Path to kubeconfig for connecting to Cluster API managed workloadcluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or kubeconfig-incluster` | +| containerSecurityContext | object | `{}` | [Security context for container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) | +| customArgs | list | `[]` | Additional custom container arguments. Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler parameters and their default values. List of arguments as strings. | +| deployment.annotations | object | `{}` | Annotations to add to the Deployment object. | +| dnsPolicy | string | `"ClusterFirst"` | Defaults to `ClusterFirst`. Valid values are: `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. If autoscaler does not depend on cluster DNS, recommended to set this to `Default`. | +| envFromConfigMap | string | `""` | ConfigMap name to use as envFrom. | +| envFromSecret | string | `""` | Secret name to use as envFrom. | +| expanderPriorities | object | `{}` | The expanderPriorities is used if `extraArgs.expander` contains `priority` and expanderPriorities is also set with the priorities. If `extraArgs.expander` contains `priority`, then expanderPriorities is used to define cluster-autoscaler-priority-expander priorities. See: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/expander/priority/readme.md | +| extraArgs | object | `{"logtostderr":true,"stderrthreshold":"info","v":4}` | Additional container arguments. Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler parameters and their default values. Everything after the first _ will be ignored allowing the use of multi-string arguments. | +| extraEnv | object | `{}` | Additional container environment variables. | +| extraEnvConfigMaps | object | `{}` | Additional container environment variables from ConfigMaps. | +| extraEnvSecrets | object | `{}` | Additional container environment variables from Secrets. | +| extraObjects | list | `[]` | Extra K8s manifests to deploy | +| extraVolumeMounts | list | `[]` | Additional volumes to mount. | +| extraVolumeSecrets | object | `{}` | Additional volumes to mount from Secrets. | +| extraVolumes | list | `[]` | Additional volumes. | +| fullnameOverride | string | `""` | String to fully override `cluster-autoscaler.fullname` template. | +| hostNetwork | bool | `false` | Whether to expose network interfaces of the host machine to pods. | +| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy | +| image.pullSecrets | list | `[]` | Image pull secrets | +| image.repository | string | `"registry.k8s.io/autoscaling/cluster-autoscaler"` | Image repository | +| image.tag | string | `"v1.32.0"` | Image tag | +| initContainers | list | `[]` | Any additional init containers. | +| kubeTargetVersionOverride | string | `""` | Allow overriding the `.Capabilities.KubeVersion.GitVersion` check. Useful for `helm template` commands. | +| kwokConfigMapName | string | `"kwok-provider-config"` | configmap for configuring kwok provider | +| magnumCABundlePath | string | `"/etc/kubernetes/ca-bundle.crt"` | Path to the host's CA bundle, from `ca-file` in the cloud-config file. | +| magnumClusterName | string | `""` | Cluster name or ID in Magnum. Required if `cloudProvider=magnum` and not setting `autoDiscovery.clusterName`. | +| nameOverride | string | `""` | String to partially override `cluster-autoscaler.fullname` template (will maintain the release name) | +| nodeSelector | object | `{}` | Node labels for pod assignment. Ref: https://kubernetes.io/docs/user-guide/node-selection/. | +| podAnnotations | object | `{}` | Annotations to add to each pod. | +| podDisruptionBudget | object | `{"maxUnavailable":1}` | Pod disruption budget. | +| podLabels | object | `{}` | Labels to add to each pod. | +| priorityClassName | string | `"system-cluster-critical"` | priorityClassName | +| priorityConfigMapAnnotations | object | `{}` | Annotations to add to `cluster-autoscaler-priority-expander` ConfigMap. | +| prometheusRule.additionalLabels | object | `{}` | Additional labels to be set in metadata. | +| prometheusRule.enabled | bool | `false` | If true, creates a Prometheus Operator PrometheusRule. | +| prometheusRule.interval | string | `nil` | How often rules in the group are evaluated (falls back to `global.evaluation_interval` if not set). | +| prometheusRule.namespace | string | `"monitoring"` | Namespace which Prometheus is running in. | +| prometheusRule.rules | list | `[]` | Rules spec template (see https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#rule). | +| rbac.clusterScoped | bool | `true` | if set to false will only provision RBAC to alter resources in the current namespace. Most useful for Cluster-API | +| rbac.create | bool | `true` | If `true`, create and use RBAC resources. | +| rbac.pspEnabled | bool | `false` | If `true`, creates and uses RBAC resources required in the cluster with [Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) enabled. Must be used with `rbac.create` set to `true`. | +| rbac.serviceAccount.annotations | object | `{}` | Additional Service Account annotations. | +| rbac.serviceAccount.automountServiceAccountToken | bool | `true` | Automount API credentials for a Service Account. | +| rbac.serviceAccount.create | bool | `true` | If `true` and `rbac.create` is also true, a Service Account will be created. | +| rbac.serviceAccount.name | string | `""` | The name of the ServiceAccount to use. If not set and create is `true`, a name is generated using the fullname template. | +| replicaCount | int | `1` | Desired number of pods | +| resources | object | `{}` | Pod resource requests and limits. | +| revisionHistoryLimit | int | `10` | The number of revisions to keep. | +| secretKeyRefNameOverride | string | `""` | Overrides the name of the Secret to use when loading the secretKeyRef for AWS, Azure and Civo env variables | +| securityContext | object | `{}` | [Security context for pod](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) | +| service.annotations | object | `{}` | Annotations to add to service | +| service.clusterIP | string | `""` | IP address to assign to service | +| service.create | bool | `true` | If `true`, a Service will be created. | +| service.externalIPs | list | `[]` | List of IP addresses at which the service is available. Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips. | +| service.labels | object | `{}` | Labels to add to service | +| service.loadBalancerIP | string | `""` | IP address to assign to load balancer (if supported). | +| service.loadBalancerSourceRanges | list | `[]` | List of IP CIDRs allowed access to load balancer (if supported). | +| service.portName | string | `"http"` | Name for service port. | +| service.servicePort | int | `8085` | Service port to expose. | +| service.type | string | `"ClusterIP"` | Type of service to create. | +| serviceMonitor.annotations | object | `{}` | Annotations to add to service monitor | +| serviceMonitor.enabled | bool | `false` | If true, creates a Prometheus Operator ServiceMonitor. | +| serviceMonitor.interval | string | `"10s"` | Interval that Prometheus scrapes Cluster Autoscaler metrics. | +| serviceMonitor.metricRelabelings | object | `{}` | MetricRelabelConfigs to apply to samples before ingestion. | +| serviceMonitor.namespace | string | `"monitoring"` | Namespace which Prometheus is running in. | +| serviceMonitor.path | string | `"/metrics"` | The path to scrape for metrics; autoscaler exposes `/metrics` (this is standard) | +| serviceMonitor.relabelings | object | `{}` | RelabelConfigs to apply to metrics before scraping. | +| serviceMonitor.selector | object | `{"release":"prometheus-operator"}` | Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install. | +| tolerations | list | `[]` | List of node taints to tolerate (requires Kubernetes >= 1.6). | +| topologySpreadConstraints | list | `[]` | You can use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. (requires Kubernetes >= 1.19). | +| updateStrategy | object | `{}` | [Deployment update strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) | +| vpa | object | `{"containerPolicy":{},"enabled":false,"updateMode":"Auto"}` | Configure a VerticalPodAutoscaler for the cluster-autoscaler Deployment. | +| vpa.containerPolicy | object | `{}` | [ContainerResourcePolicy](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L159). The containerName is always et to the deployment's container name. This value is required if VPA is enabled. | +| vpa.enabled | bool | `false` | If true, creates a VerticalPodAutoscaler. | +| vpa.updateMode | string | `"Auto"` | [UpdateMode](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L124) | diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md.gotmpl b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md.gotmpl new file mode 100644 index 000000000..786dbec1d --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/README.md.gotmpl @@ -0,0 +1,417 @@ +{{ template "chart.header" . }} + +{{ template "chart.description" . }} + +## TL;DR + +```console +$ helm repo add autoscaler https://kubernetes.github.io/autoscaler + +# Method 1 - Using Autodiscovery +$ helm install my-release autoscaler/cluster-autoscaler \ + --set 'autoDiscovery.clusterName'= + +# Method 2 - Specifying groups manually +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +## Introduction + +This chart bootstraps a cluster-autoscaler deployment on a [Kubernetes](http://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager. + +## Prerequisites + +- Helm 3+ +- Kubernetes 1.8+ + - [Older versions](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler#releases) may work by overriding the `image`. Cluster autoscaler internally simulates the scheduler and bugs between mismatched versions may be subtle. +- Azure AKS specific Prerequisites: + - Kubernetes 1.10+ with RBAC-enabled. + +## Previous Helm Chart + +The previous `cluster-autoscaler` Helm chart hosted at [helm/charts](https://github.com/helm/charts) has been moved to this repository in accordance with the [Deprecation timeline](https://github.com/helm/charts#deprecation-timeline). Note that a few things have changed between this version and the old version: + +- This repository **only** supports Helm chart installations using Helm 3+ since the `apiVersion` on the charts has been marked as `v2`. +- Previous versions of the Helm chart have not been migrated + +## Migration from 1.X to 9.X+ versions of this Chart + +**TL;DR:** +You should choose to use versions >=9.0.0 of the `cluster-autoscaler` chart published from this repository; previous versions, and the `cluster-autoscaler-chart` with versioning 1.X.X published from this repository are deprecated. + +
+ Previous versions of this chart - further details +On initial migration of this chart from the `helm/charts` repository this chart was renamed from `cluster-autoscaler` to `cluster-autoscaler-chart` due to technical limitations. This affected all `1.X` releases of the chart, version 2.0.0 of this chart exists only to mark the [`cluster-autoscaler-chart` chart](https://artifacthub.io/packages/helm/cluster-autoscaler/cluster-autoscaler-chart) as deprecated. + +Releases of the chart from `9.0.0` onwards return the naming of the chart to `cluster-autoscaler` and return to following the versioning established by the chart's previous location at . + +To migrate from a 1.X release of the chart to a `9.0.0` or later release, you should first uninstall your `1.X` install of the `cluster-autoscaler-chart` chart, before performing the installation of the new `cluster-autoscaler` chart. +
+ +## Migration from 9.0 to 9.1 + +Starting from `9.1.0` the `envFromConfigMap` value is expected to contain the name of a ConfigMap that is used as ref for `envFrom`, similar to `envFromSecret`. If you want to keep the previous behaviour of `envFromConfigMap` you must rename it to `extraEnvConfigMaps`. + +## Installing the Chart + +**By default, no deployment is created and nothing will autoscale**. + +You must provide some minimal configuration, either to specify instance groups or enable auto-discovery. It is not recommended to do both. + +Either: + +- Set `autoDiscovery.clusterName` and provide additional autodiscovery options if necessary **or** +- Set static node group configurations for one or more node groups (using `autoscalingGroups` or `autoscalingGroupsnamePrefix`). + +To create a valid configuration, follow instructions for your cloud provider: + +- [AWS](#aws---using-auto-discovery-of-tagged-instance-groups) +- [GCE](#gce) +- [Azure](#azure) +- [OpenStack Magnum](#openstack-magnum) +- [Cluster API](#cluster-api) +- [Exoscale](#exoscale) +- [Hetzner Cloud](#hetzner-cloud) +- [Civo](#civo) + +### Templating the autoDiscovery.clusterName + +The cluster name can be templated in the `autoDiscovery.clusterName` variable. This is useful when the cluster name is dynamically generated based on other values coming from external systems like Argo CD or Flux. This also allows you to use global Helm values to set the cluster name, e.g., `autoDiscovery.clusterName=\{\{ .Values.global.clusterName }}`, so that you don't need to set it in more than 1 location in the values file. + +### AWS - Using auto-discovery of tagged instance groups + +Auto-discovery finds ASGs tags as below and automatically manages them based on the min and max size specified in the ASG. `cloudProvider=aws` only. + +- Tag the ASGs with keys to match `.Values.autoDiscovery.tags`, by default: `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/` +- Verify the [IAM Permissions](#aws---iam) +- Set `autoDiscovery.clusterName=` +- Set `awsRegion=` +- Set (option) `awsAccessKeyID=` and `awsSecretAccessKey=` if you want to [use AWS credentials directly instead of an instance role](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials) + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= +``` + +Alternatively with your own AWS credentials + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set autoDiscovery.clusterName= \ + --set awsRegion= \ + --set awsAccessKeyID= \ + --set awsSecretAccessKey= +``` + +#### Specifying groups manually + +Without autodiscovery, specify an array of elements each containing ASG name, min size, max size. The sizes specified here will be applied to the ASG, assuming IAM permissions are correctly configured. + +- Verify the [IAM Permissions](#aws---iam) +- Either provide a yaml file setting `autoscalingGroups` (see values.yaml) or use `--set` e.g.: + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroups[0].name=your-asg-name" \ + --set "autoscalingGroups[0].maxSize=10" \ + --set "autoscalingGroups[0].minSize=1" +``` + +#### Auto-discovery + +For auto-discovery of instances to work, they must be tagged with the keys in `.Values.autoDiscovery.tags`, which by default are `k8s.io/cluster-autoscaler/enabled` and `k8s.io/cluster-autoscaler/`. + +The value of the tag does not matter, only the key. + +An example kops spec excerpt: + +```yaml +apiVersion: kops/v1alpha2 +kind: Cluster +metadata: + name: my.cluster.internal +spec: + additionalPolicies: + node: | + [ + {"Effect":"Allow","Action":["autoscaling:DescribeAutoScalingGroups","autoscaling:DescribeAutoScalingInstances","autoscaling:DescribeLaunchConfigurations","autoscaling:DescribeTags","autoscaling:SetDesiredCapacity","autoscaling:TerminateInstanceInAutoScalingGroup"],"Resource":"*"} + ] + ... +--- +apiVersion: kops/v1alpha2 +kind: InstanceGroup +metadata: + labels: + kops.k8s.io/cluster: my.cluster.internal + name: my-instances +spec: + cloudLabels: + k8s.io/cluster-autoscaler/enabled: "" + k8s.io/cluster-autoscaler/my.cluster.internal: "" + image: kops.io/k8s-1.8-debian-jessie-amd64-hvm-ebs-2018-01-14 + machineType: r4.large + maxSize: 4 + minSize: 0 +``` + +In this example you would need to `--set autoDiscovery.clusterName=my.cluster.internal` when installing. + +It is not recommended to try to mix this with setting `autoscalingGroups`. + +See [autoscaler AWS documentation](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup) for a more discussion of the setup. + +### GCE + +The following parameters are required: + +- `autoDiscovery.clusterName=any-name` +- `cloud-provider=gce` +- `autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefix[0].minSize=1` + +To use Managed Instance Group (MIG) auto-discovery, provide a YAML file setting `autoscalingGroupsnamePrefix` (see values.yaml) or use `--set` when installing the Chart - e.g. + +```console +$ helm install my-release autoscaler/cluster-autoscaler \ + --set "autoscalingGroupsnamePrefix[0].name=your-ig-prefix,autoscalingGroupsnamePrefix[0].maxSize=10,autoscalingGroupsnamePrefi[0].minSize=1" \ + --set autoDiscovery.clusterName= \ + --set cloudProvider=gce +``` + +Note that `your-ig-prefix` should be a _prefix_ matching one or more MIGs, and _not_ the full name of the MIG. For example, to match multiple instance groups - `k8s-node-group-a-standard`, `k8s-node-group-b-gpu`, you would use a prefix of `k8s-node-group-`. + +In the event you want to explicitly specify MIGs instead of using auto-discovery, set members of the `autoscalingGroups` array directly - e.g. + +``` +# where 'n' is the index, starting at 0 +--set autoscalingGroups[n].name=https://content.googleapis.com/compute/v1/projects/$PROJECTID/zones/$ZONENAME/instanceGroups/$FULL-MIG-NAME,autoscalingGroups[n].maxSize=$MAXSIZE,autoscalingGroups[n].minSize=$MINSIZE +``` + +### Azure + +The following parameters are required: + +- `cloudProvider=azure` +- `autoscalingGroups[0].name=your-vmss,autoscalingGroups[0].maxSize=10,autoscalingGroups[0].minSize=1` +- `azureClientID: "your-service-principal-app-id"` +- `azureClientSecret: "your-service-principal-client-secret"` +- `azureSubscriptionID: "your-azure-subscription-id"` +- `azureTenantID: "your-azure-tenant-id"` +- `azureResourceGroup: "your-aks-cluster-resource-group-name"` +- `azureVMType: "vmss"` + +### OpenStack Magnum + +`cloudProvider: magnum` must be set, and then one of + +- `magnumClusterName=` and `autoscalingGroups` with the names of node groups and min/max node counts +- or `autoDiscovery.clusterName=` with one or more `autoDiscovery.roles`. + +Additionally, `cloudConfigPath: "/etc/kubernetes/cloud-config"` must be set as this should be the location of the cloud-config file on the host. + +Example values files can be found [here](../../cluster-autoscaler/cloudprovider/magnum/examples). + +Install the chart with + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f myvalues.yaml +``` + +### Cluster-API + +`cloudProvider: clusterapi` must be set, and then one or more of + +- `autoDiscovery.clusterName` +- or `autoDiscovery.namespace` +- or `autoDiscovery.labels` + +See [here](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery) for more details. + +Additional config parameters available, see the `values.yaml` for more details + +- `clusterAPIMode` +- `clusterAPIKubeconfigSecret` +- `clusterAPIWorkloadKubeconfigPath` +- `clusterAPICloudConfigPath` + +### Exoscale + +Create a `values.yaml` file with the following content: +```yaml +cloudProvider: exoscale +autoDiscovery: + clusterName: cluster.local # this value is not used, but must be set +``` + +Optionally, you may specify the minimum and maximum size of a particular nodepool by adding the following to the `values.yaml` file: +```yaml +autoscalingGroups: + - name: your-nodepool-name + maxSize: 10 + minSize: 1 +``` + +Create an Exoscale API key with appropriate permissions as described in [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md). +A secret of name `-exoscale-cluster-autoscaler` needs to be created, containing the api key and secret, as well as the zone. + +```console +$ kubectl create secret generic my-release-exoscale-cluster-autoscaler \ + --from-literal=api-key="EXOxxxxxxxxxxxxxxxxxxxxxxxx" \ + --from-literal=api-secret="xxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" --from-literal=api-zone="ch-gva-2" +``` + +After creating the secret, the chart may be installed: + +```console +$ helm install my-release autoscaler/cluster-autoscaler -f values.yaml +``` + +Read [cluster-autoscaler/cloudprovider/exoscale/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/exoscale/README.md) for further information on the setup without helm. + +### Hetzner Cloud + +The following parameters are required: + +- `cloudProvider=hetzner` +- `extraEnv.HCLOUD_TOKEN=...` +- `autoscalingGroups=...` + +Each autoscaling group requires an additional `instanceType` and `region` key to be set. + +Read [cluster-autoscaler/cloudprovider/hetzner/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/hetzner/README.md) for further information on the setup without helm. + +### Civo + +The following parameters are required: + +- `cloudProvider=civo` +- `autoscalingGroups=...` + +When installing the helm chart to the namespace `kube-system`, you can set `secretKeyRefNameOverride` to `civo-api-access`. +Otherwise specify the following parameters: + +- `civoApiUrl=https://api.civo.com` +- `civoApiKey=...` +- `civoClusterID=...` +- `civoRegion=...` + +Read [cluster-autoscaler/cloudprovider/civo/README.md](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/civo/README.md) for further information on the setup without helm. + +## Uninstalling the Chart + +To uninstall `my-release`: + +```console +$ helm uninstall my-release +``` + +The command removes all the Kubernetes components associated with the chart and deletes the release. + +> **Tip**: List all releases using `helm list` or start clean with `helm uninstall my-release` + +## Additional Configuration + +### AWS - IAM + +The worker running the cluster autoscaler will need access to certain resources and actions depending on the version you run and your configuration of it. + +For the up-to-date IAM permissions required, please see the [cluster autoscaler's AWS Cloudprovider Readme](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#iam-policy) and switch to the tag of the cluster autoscaler image you are using. + +### AWS - IAM Roles for Service Accounts (IRSA) + +For Kubernetes clusters that use Amazon EKS, the service account can be configured with an IAM role using [IAM Roles for Service Accounts](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts.html) to avoid needing to grant access to the worker nodes for AWS resources. + +In order to accomplish this, you will first need to create a new IAM role with the above mentions policies. Take care in [configuring the trust relationship](https://docs.aws.amazon.com/eks/latest/userguide/iam-roles-for-service-accounts-technical-overview.html#iam-role-configuration) to restrict access just to the service account used by cluster autoscaler. + +Once you have the IAM role configured, you would then need to `--set rbac.serviceAccount.annotations."eks\.amazonaws\.com/role-arn"=arn:aws:iam::123456789012:role/MyRoleName` when installing. + +### Azure - Using azure workload identity + +You can use the project [Azure workload identity](https://github.com/Azure/azure-workload-identity), to automatically configure the correct setup for your pods to used federated identity with Azure. + +You can also set the correct settings yourself instead of relying on this project. + +For example the following configuration will configure the Autoscaler to use your federated identity: + +```yaml +azureUseWorkloadIdentityExtension: true +extraEnv: + AZURE_CLIENT_ID: USER ASSIGNED IDENTITY CLIENT ID + AZURE_TENANT_ID: USER ASSIGNED IDENTITY TENANT ID + AZURE_FEDERATED_TOKEN_FILE: /var/run/secrets/tokens/azure-identity-token + AZURE_AUTHORITY_HOST: https://login.microsoftonline.com/ +extraVolumes: +- name: azure-identity-token + projected: + defaultMode: 420 + sources: + - serviceAccountToken: + audience: api://AzureADTokenExchange + expirationSeconds: 3600 + path: azure-identity-token +extraVolumeMounts: +- mountPath: /var/run/secrets/tokens + name: azure-identity-token + readOnly: true +``` + +### Custom arguments + +You can use the `customArgs` value to give any argument to cluster autoscaler command. + +Typical use case is to give an environment variable as an argument which will be interpolated at execution time. + +This is helpful when you need to inject values from configmap or secret. + +## Troubleshooting + +The chart will succeed even if the container arguments are incorrect. A few minutes after starting `kubectl logs -l "app=aws-cluster-autoscaler" --tail=50` should loop through something like + +``` +polling_autoscaler.go:111] Poll finished +static_autoscaler.go:97] Starting main loop +utils.go:435] No pod using affinity / antiaffinity found in cluster, disabling affinity predicate for this loop +static_autoscaler.go:230] Filtering out schedulables +``` + +If not, find a pod that the deployment created and `describe` it, paying close attention to the arguments under `Command`. e.g.: + +``` +Containers: + cluster-autoscaler: + Command: + ./cluster-autoscaler + --cloud-provider=aws +# if specifying ASGs manually + --nodes=1:10:your-scaling-group-name +# if using autodiscovery + --node-group-auto-discovery=asg:tag=k8s.io/cluster-autoscaler/enabled,k8s.io/cluster-autoscaler/ + --v=4 +``` + +### PodSecurityPolicy + +Though enough for the majority of installations, the default PodSecurityPolicy _could_ be too restrictive depending on the specifics of your release. Please make sure to check that the template fits with any customizations made or disable it by setting `rbac.pspEnabled` to `false`. + +### VerticalPodAutoscaler + +The CA Helm Chart can install a [`VerticalPodAutoscaler`](https://github.com/kubernetes/autoscaler/blob/master/vertical-pod-autoscaler/README.md) object from Chart version `9.27.0` +onwards for the Cluster Autoscaler Deployment to scale the CA as appropriate, but for that, we +need to install the VPA to the cluster separately. A VPA can help minimize wasted resources +when usage spikes periodically or remediate containers that are being OOMKilled. + +The following example snippet can be used to install VPA that allows scaling down from the default recommendations of the deployment template: + +```yaml +vpa: + enabled: true + containerPolicy: + minAllowed: + cpu: 20m + memory: 50Mi +``` + +{{ template "chart.valuesSection" . }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/NOTES.txt b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/NOTES.txt new file mode 100644 index 000000000..1a87a3d10 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/NOTES.txt @@ -0,0 +1,18 @@ +{{- if or ( or .Values.autoDiscovery.clusterName .Values.autoDiscovery.namespace .Values.autoDiscovery.labels ) .Values.autoscalingGroups }} + +To verify that cluster-autoscaler has started, run: + + kubectl --namespace={{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ template "cluster-autoscaler.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" + +{{- else -}} + +############################################################################## +#### ERROR: You must specify values for either #### +#### autoDiscovery or autoscalingGroups[] #### +############################################################################## + +The deployment and pod will not be created and the installation is not functional +See README: + open https://github.com/kubernetes/autoscaler/tree/master/charts/cluster-autoscaler + +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/_helpers.tpl b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/_helpers.tpl new file mode 100644 index 000000000..c7e80f4d8 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/_helpers.tpl @@ -0,0 +1,160 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "cluster-autoscaler.name" -}} +{{- default (printf "%s-%s" .Values.cloudProvider .Chart.Name) .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "cluster-autoscaler.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default (printf "%s-%s" .Values.cloudProvider .Chart.Name) .Values.nameOverride -}} +{{- if ne $name .Release.Name -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s" $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cluster-autoscaler.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Return instance and name labels. +*/}} +{{- define "cluster-autoscaler.instance-name" -}} +app.kubernetes.io/instance: {{ .Release.Name | quote }} +app.kubernetes.io/name: {{ include "cluster-autoscaler.name" . | quote }} +{{- end -}} + + +{{/* +Return labels, including instance and name. +*/}} +{{- define "cluster-autoscaler.labels" -}} +{{ include "cluster-autoscaler.instance-name" . }} +app.kubernetes.io/managed-by: {{ .Release.Service | quote }} +helm.sh/chart: {{ include "cluster-autoscaler.chart" . | quote }} +{{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels }} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for deployment. +*/}} +{{- define "deployment.apiVersion" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "<1.9-0" $kubeTargetVersion -}} +{{- print "apps/v1beta2" -}} +{{- else -}} +{{- print "apps/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podsecuritypolicy. +*/}} +{{- define "podsecuritypolicy.apiVersion" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "<1.10-0" $kubeTargetVersion -}} +{{- print "extensions/v1beta1" -}} +{{- else -}} +{{- print "policy/v1beta1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the appropriate apiVersion for podDisruptionBudget. +*/}} +{{- define "podDisruptionBudget.apiVersion" -}} +{{- $kubeTargetVersion := default .Capabilities.KubeVersion.GitVersion .Values.kubeTargetVersionOverride }} +{{- if semverCompare "<1.21-0" $kubeTargetVersion -}} +{{- print "policy/v1beta1" -}} +{{- else -}} +{{- print "policy/v1" -}} +{{- end -}} +{{- end -}} + +{{/* +Return the service account name used by the pod. +*/}} +{{- define "cluster-autoscaler.serviceAccountName" -}} +{{- if .Values.rbac.serviceAccount.create -}} + {{ default (include "cluster-autoscaler.fullname" .) .Values.rbac.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.rbac.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Return true if the priority expander is enabled +*/}} +{{- define "cluster-autoscaler.priorityExpanderEnabled" -}} +{{- $expanders := splitList "," (default "" .Values.extraArgs.expander) -}} +{{- if has "priority" $expanders -}} +{{- true -}} +{{- end -}} +{{- end -}} + +{{/* +autoDiscovery.clusterName for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscovery.clusterName" -}} +{{- print "clusterName=" -}}{{ tpl (.Values.autoDiscovery.clusterName) . }} +{{- end -}} + +{{/* +autoDiscovery.namespace for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscovery.namespace" -}} +{{- print "namespace=" }}{{ .Values.autoDiscovery.namespace -}} +{{- end -}} + +{{/* +autoDiscovery.labels for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscovery.labels" -}} +{{- range $i, $el := .Values.autoDiscovery.labels -}} +{{- if $i -}}{{- print "," -}}{{- end -}} +{{- range $key, $val := $el -}} +{{- $key -}}{{- print "=" -}}{{- $val -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Return the autodiscoveryparameters for clusterapi. +*/}} +{{- define "cluster-autoscaler.capiAutodiscoveryConfig" -}} +{{- if .Values.autoDiscovery.clusterName -}} +{{ include "cluster-autoscaler.capiAutodiscovery.clusterName" . }} + {{- if .Values.autoDiscovery.namespace }} + {{- print "," -}} + {{ include "cluster-autoscaler.capiAutodiscovery.namespace" . }} + {{- end -}} + {{- if .Values.autoDiscovery.labels }} + {{- print "," -}} + {{ include "cluster-autoscaler.capiAutodiscovery.labels" . }} + {{- end -}} +{{- else if .Values.autoDiscovery.namespace -}} +{{ include "cluster-autoscaler.capiAutodiscovery.namespace" . }} + {{- if .Values.autoDiscovery.labels }} + {{- print "," -}} + {{ include "cluster-autoscaler.capiAutodiscovery.labels" . }} + {{- end -}} +{{- else if .Values.autoDiscovery.labels -}} + {{ include "cluster-autoscaler.capiAutodiscovery.labels" . }} +{{- end -}} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrole.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrole.yaml new file mode 100644 index 000000000..7e23ec28a --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrole.yaml @@ -0,0 +1,176 @@ +{{- if and .Values.rbac.create .Values.rbac.clusterScoped -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} +rules: + - apiGroups: + - "" + resources: + - events + - endpoints + verbs: + - create + - patch + - apiGroups: + - "" + resources: + - pods/eviction + verbs: + - create + - apiGroups: + - "" + resources: + - pods/status + verbs: + - update + - apiGroups: + - "" + resources: + - endpoints + resourceNames: + - cluster-autoscaler + verbs: + - get + - update + - apiGroups: + - "" + resources: + - nodes + verbs: + - watch + - list + - create + - delete + - get + - update + - apiGroups: + - "" + resources: + - namespaces + - pods + - services + - replicationcontrollers + - persistentvolumeclaims + - persistentvolumes + verbs: + - watch + - list + - get + - apiGroups: + - batch + resources: + - jobs + - cronjobs + verbs: + - watch + - list + - get + - apiGroups: + - batch + - extensions + resources: + - jobs + verbs: + - get + - list + - patch + - watch + - apiGroups: + - extensions + resources: + - replicasets + - daemonsets + verbs: + - watch + - list + - get + - apiGroups: + - policy + resources: + - poddisruptionbudgets + verbs: + - watch + - list + - apiGroups: + - apps + resources: + - daemonsets + - replicasets + - statefulsets + verbs: + - watch + - list + - get + - apiGroups: + - storage.k8s.io + resources: + - storageclasses + - csinodes + - csidrivers + - csistoragecapacities + - volumeattachments + verbs: + - watch + - list + - get + - apiGroups: + - "" + resources: + - configmaps + verbs: + - list + - watch + - get + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - apiGroups: + - coordination.k8s.io + resourceNames: + - cluster-autoscaler + resources: + - leases + verbs: + - get + - update +{{- if .Values.rbac.pspEnabled }} + - apiGroups: + - extensions + - policy + resources: + - podsecuritypolicies + resourceNames: + - {{ template "cluster-autoscaler.fullname" . }} + verbs: + - use +{{- end -}} +{{- if and ( and ( eq .Values.cloudProvider "clusterapi" ) ( .Values.rbac.clusterScoped ) ( or ( eq .Values.clusterAPIMode "incluster-incluster" ) ( eq .Values.clusterAPIMode "kubeconfig-incluster" ) ))}} + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments + - machinepools + - machines + - machinesets + verbs: + - get + - list + - update + - watch + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments/scale + - machinepools/scale + verbs: + - get + - patch + - update +{{- end }} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrolebinding.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..d2384dc62 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/clusterrolebinding.yaml @@ -0,0 +1,16 @@ +{{- if and .Values.rbac.create .Values.rbac.clusterScoped -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ template "cluster-autoscaler.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "cluster-autoscaler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/configmap.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/configmap.yaml new file mode 100644 index 000000000..6cd0c4064 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/configmap.yaml @@ -0,0 +1,416 @@ +{{- if or (eq .Values.cloudProvider "kwok") }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.kwokConfigMapName | default "kwok-provider-config" }} + namespace: {{ .Release.Namespace }} +data: + config: |- + # if you see '\n' everywhere, remove all the trailing spaces + apiVersion: v1alpha1 + readNodesFrom: configmap # possible values: [cluster,configmap] + nodegroups: + # to specify how to group nodes into a nodegroup + # e.g., you want to treat nodes with same instance type as a nodegroup + # node1: m5.xlarge + # node2: c5.xlarge + # node3: m5.xlarge + # nodegroup1: [node1,node3] + # nodegroup2: [node2] + fromNodeLabelKey: "kwok-nodegroup" + # you can either specify fromNodeLabelKey OR fromNodeAnnotation + # (both are not allowed) + # fromNodeAnnotation: "eks.amazonaws.com/nodegroup" + nodes: + # gpuConfig: + # # to tell kwok provider what label should be considered as GPU label + # gpuLabelKey: "k8s.amazonaws.com/accelerator" + # availableGPUTypes: + # "nvidia-tesla-k80": {} + # "nvidia-tesla-p100": {} + configmap: + name: kwok-provider-templates + kwok: {} # default: fetch latest release of kwok from github and install it + # # you can also manually specify which kwok release you want to install + # # for example: + # kwok: + # release: v0.3.0 + # # you can also disable installing kwok in CA code (and install your own kwok release) + # kwok: + # install: false (true if not specified) +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: kwok-provider-templates + namespace: {{ .Release.Namespace }} +data: + templates: |- + # if you see '\n' everywhere, remove all the trailing spaces + apiVersion: v1 + items: + - apiVersion: v1 + kind: Node + metadata: + annotations: + kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock + node.alpha.kubernetes.io/ttl: "0" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2023-05-31T04:39:16Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: kind-control-plane + kwok-nodegroup: control-plane + kubernetes.io/os: linux + node-role.kubernetes.io/control-plane: "" + node.kubernetes.io/exclude-from-external-load-balancers: "" + name: kind-control-plane + resourceVersion: "506" + uid: 86716ec7-3071-4091-b055-77b4361d1dca + spec: + podCIDR: 10.244.0.0/24 + podCIDRs: + - 10.244.0.0/24 + providerID: kind://docker/kind/kind-control-plane + taints: + - effect: NoSchedule + key: node-role.kubernetes.io/control-plane + status: + addresses: + - address: 172.18.0.2 + type: InternalIP + - address: kind-control-plane + type: Hostname + allocatable: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + capacity: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + conditions: + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:13Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:13Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:13Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2023-05-31T04:39:58Z" + lastTransitionTime: "2023-05-31T04:39:46Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - registry.k8s.io/etcd:3.5.6-0 + sizeBytes: 102542580 + - names: + - docker.io/library/import-2023-03-30@sha256:ba097b515c8c40689733c0f19de377e9bf8995964b7d7150c2045f3dfd166657 + - registry.k8s.io/kube-apiserver:v1.26.3 + sizeBytes: 80392681 + - names: + - docker.io/library/import-2023-03-30@sha256:8dbb345de79d1c44f59a7895da702a5f71997ae72aea056609445c397b0c10dc + - registry.k8s.io/kube-controller-manager:v1.26.3 + sizeBytes: 68538487 + - names: + - docker.io/library/import-2023-03-30@sha256:44db4d50a5f9c8efbac0d37ea974d1c0419a5928f90748d3d491a041a00c20b5 + - registry.k8s.io/kube-proxy:v1.26.3 + sizeBytes: 67217404 + - names: + - docker.io/library/import-2023-03-30@sha256:3dd2337f70af979c7362b5e52bbdfcb3a5fd39c78d94d02145150cd2db86ba39 + - registry.k8s.io/kube-scheduler:v1.26.3 + sizeBytes: 57761399 + - names: + - docker.io/kindest/kindnetd:v20230330-48f316cd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + - docker.io/kindest/kindnetd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + sizeBytes: 27726335 + - names: + - docker.io/kindest/local-path-provisioner:v0.0.23-kind.0@sha256:f2d0a02831ff3a03cf51343226670d5060623b43a4cfc4808bd0875b2c4b9501 + sizeBytes: 18664669 + - names: + - registry.k8s.io/coredns/coredns:v1.9.3 + sizeBytes: 14837849 + - names: + - docker.io/kindest/local-path-helper:v20230330-48f316cd@sha256:135203f2441f916fb13dad1561d27f60a6f11f50ec288b01a7d2ee9947c36270 + sizeBytes: 3052037 + - names: + - registry.k8s.io/pause:3.7 + sizeBytes: 311278 + nodeInfo: + architecture: amd64 + bootID: 2d71b318-5d07-4de2-9e61-2da28cf5bbf0 + containerRuntimeVersion: containerd://1.6.19-46-g941215f49 + kernelVersion: 5.15.0-72-generic + kubeProxyVersion: v1.26.3 + kubeletVersion: v1.26.3 + machineID: 96f8c8b8c8ae4600a3654341f207586e + operatingSystem: linux + osImage: Ubuntu 22.04.2 LTS + systemUUID: 111aa932-7f99-4bef-aaf7-36aa7fb9b012 + - apiVersion: v1 + kind: Node + metadata: + annotations: + kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock + node.alpha.kubernetes.io/ttl: "0" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2023-05-31T04:39:57Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: kind-worker + kwok-nodegroup: kind-worker + kubernetes.io/os: linux + name: kind-worker + resourceVersion: "577" + uid: 2ac0eb71-e5cf-4708-bbbf-476e8f19842b + spec: + podCIDR: 10.244.2.0/24 + podCIDRs: + - 10.244.2.0/24 + providerID: kind://docker/kind/kind-worker + status: + addresses: + - address: 172.18.0.3 + type: InternalIP + - address: kind-worker + type: Hostname + allocatable: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + capacity: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + conditions: + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:40:05Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - registry.k8s.io/etcd:3.5.6-0 + sizeBytes: 102542580 + - names: + - docker.io/library/import-2023-03-30@sha256:ba097b515c8c40689733c0f19de377e9bf8995964b7d7150c2045f3dfd166657 + - registry.k8s.io/kube-apiserver:v1.26.3 + sizeBytes: 80392681 + - names: + - docker.io/library/import-2023-03-30@sha256:8dbb345de79d1c44f59a7895da702a5f71997ae72aea056609445c397b0c10dc + - registry.k8s.io/kube-controller-manager:v1.26.3 + sizeBytes: 68538487 + - names: + - docker.io/library/import-2023-03-30@sha256:44db4d50a5f9c8efbac0d37ea974d1c0419a5928f90748d3d491a041a00c20b5 + - registry.k8s.io/kube-proxy:v1.26.3 + sizeBytes: 67217404 + - names: + - docker.io/library/import-2023-03-30@sha256:3dd2337f70af979c7362b5e52bbdfcb3a5fd39c78d94d02145150cd2db86ba39 + - registry.k8s.io/kube-scheduler:v1.26.3 + sizeBytes: 57761399 + - names: + - docker.io/kindest/kindnetd:v20230330-48f316cd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + - docker.io/kindest/kindnetd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + sizeBytes: 27726335 + - names: + - docker.io/kindest/local-path-provisioner:v0.0.23-kind.0@sha256:f2d0a02831ff3a03cf51343226670d5060623b43a4cfc4808bd0875b2c4b9501 + sizeBytes: 18664669 + - names: + - registry.k8s.io/coredns/coredns:v1.9.3 + sizeBytes: 14837849 + - names: + - docker.io/kindest/local-path-helper:v20230330-48f316cd@sha256:135203f2441f916fb13dad1561d27f60a6f11f50ec288b01a7d2ee9947c36270 + sizeBytes: 3052037 + - names: + - registry.k8s.io/pause:3.7 + sizeBytes: 311278 + nodeInfo: + architecture: amd64 + bootID: 2d71b318-5d07-4de2-9e61-2da28cf5bbf0 + containerRuntimeVersion: containerd://1.6.19-46-g941215f49 + kernelVersion: 5.15.0-72-generic + kubeProxyVersion: v1.26.3 + kubeletVersion: v1.26.3 + machineID: a98a13ff474d476294935341f1ba9816 + operatingSystem: linux + osImage: Ubuntu 22.04.2 LTS + systemUUID: 5f3c1af8-a385-4776-85e4-73d7f4252b44 + - apiVersion: v1 + kind: Node + metadata: + annotations: + kubeadm.alpha.kubernetes.io/cri-socket: unix:///run/containerd/containerd.sock + node.alpha.kubernetes.io/ttl: "0" + volumes.kubernetes.io/controller-managed-attach-detach: "true" + creationTimestamp: "2023-05-31T04:39:57Z" + labels: + beta.kubernetes.io/arch: amd64 + beta.kubernetes.io/os: linux + kubernetes.io/arch: amd64 + kubernetes.io/hostname: kind-worker2 + kwok-nodegroup: kind-worker2 + kubernetes.io/os: linux + name: kind-worker2 + resourceVersion: "578" + uid: edc7df38-feb2-4089-9955-780562bdd21e + spec: + podCIDR: 10.244.1.0/24 + podCIDRs: + - 10.244.1.0/24 + providerID: kind://docker/kind/kind-worker2 + status: + addresses: + - address: 172.18.0.4 + type: InternalIP + - address: kind-worker2 + type: Hostname + allocatable: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + capacity: + cpu: "12" + ephemeral-storage: 959786032Ki + hugepages-1Gi: "0" + hugepages-2Mi: "0" + memory: 32781516Ki + pods: "110" + conditions: + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient memory available + reason: KubeletHasSufficientMemory + status: "False" + type: MemoryPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has no disk pressure + reason: KubeletHasNoDiskPressure + status: "False" + type: DiskPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:39:57Z" + message: kubelet has sufficient PID available + reason: KubeletHasSufficientPID + status: "False" + type: PIDPressure + - lastHeartbeatTime: "2023-05-31T04:40:17Z" + lastTransitionTime: "2023-05-31T04:40:08Z" + message: kubelet is posting ready status + reason: KubeletReady + status: "True" + type: Ready + daemonEndpoints: + kubeletEndpoint: + Port: 10250 + images: + - names: + - registry.k8s.io/etcd:3.5.6-0 + sizeBytes: 102542580 + - names: + - docker.io/library/import-2023-03-30@sha256:ba097b515c8c40689733c0f19de377e9bf8995964b7d7150c2045f3dfd166657 + - registry.k8s.io/kube-apiserver:v1.26.3 + sizeBytes: 80392681 + - names: + - docker.io/library/import-2023-03-30@sha256:8dbb345de79d1c44f59a7895da702a5f71997ae72aea056609445c397b0c10dc + - registry.k8s.io/kube-controller-manager:v1.26.3 + sizeBytes: 68538487 + - names: + - docker.io/library/import-2023-03-30@sha256:44db4d50a5f9c8efbac0d37ea974d1c0419a5928f90748d3d491a041a00c20b5 + - registry.k8s.io/kube-proxy:v1.26.3 + sizeBytes: 67217404 + - names: + - docker.io/library/import-2023-03-30@sha256:3dd2337f70af979c7362b5e52bbdfcb3a5fd39c78d94d02145150cd2db86ba39 + - registry.k8s.io/kube-scheduler:v1.26.3 + sizeBytes: 57761399 + - names: + - docker.io/kindest/kindnetd:v20230330-48f316cd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + - docker.io/kindest/kindnetd@sha256:c19d6362a6a928139820761475a38c24c0cf84d507b9ddf414a078cf627497af + sizeBytes: 27726335 + - names: + - docker.io/kindest/local-path-provisioner:v0.0.23-kind.0@sha256:f2d0a02831ff3a03cf51343226670d5060623b43a4cfc4808bd0875b2c4b9501 + sizeBytes: 18664669 + - names: + - registry.k8s.io/coredns/coredns:v1.9.3 + sizeBytes: 14837849 + - names: + - docker.io/kindest/local-path-helper:v20230330-48f316cd@sha256:135203f2441f916fb13dad1561d27f60a6f11f50ec288b01a7d2ee9947c36270 + sizeBytes: 3052037 + - names: + - registry.k8s.io/pause:3.7 + sizeBytes: 311278 + nodeInfo: + architecture: amd64 + bootID: 2d71b318-5d07-4de2-9e61-2da28cf5bbf0 + containerRuntimeVersion: containerd://1.6.19-46-g941215f49 + kernelVersion: 5.15.0-72-generic + kubeProxyVersion: v1.26.3 + kubeletVersion: v1.26.3 + machineID: fa9f4cd3b3a743bc867b04e44941dcb2 + operatingSystem: linux + osImage: Ubuntu 22.04.2 LTS + systemUUID: f36c0f00-8ba5-4c8c-88bc-2981c8d377b9 + kind: List + metadata: + resourceVersion: "" + + +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/deployment.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/deployment.yaml new file mode 100644 index 000000000..a566a01ce --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/deployment.yaml @@ -0,0 +1,372 @@ +{{- if or ( or .Values.autoDiscovery.clusterName .Values.autoDiscovery.namespace .Values.autoDiscovery.labels ) .Values.autoscalingGroups }} +{{/* one of the above is required */}} +apiVersion: {{ template "deployment.apiVersion" . }} +kind: Deployment +metadata: + annotations: +{{ toYaml .Values.deployment.annotations | indent 4 }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + replicas: {{ .Values.replicaCount }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + selector: + matchLabels: +{{ include "cluster-autoscaler.instance-name" . | indent 6 }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 6 }} + {{- end }} +{{- if .Values.updateStrategy }} + strategy: + {{ toYaml .Values.updateStrategy | nindent 4 | trim }} +{{- end }} + template: + metadata: + {{- if .Values.podAnnotations }} + annotations: +{{ toYaml .Values.podAnnotations | indent 8 }} + {{- end }} + labels: +{{ include "cluster-autoscaler.instance-name" . | indent 8 }} + {{- if .Values.additionalLabels }} +{{ toYaml .Values.additionalLabels | indent 8 }} + {{- end }} + {{- if .Values.podLabels }} +{{ toYaml .Values.podLabels | indent 8 }} + {{- end }} + spec: + {{- if .Values.priorityClassName }} + priorityClassName: "{{ .Values.priorityClassName }}" + {{- end }} + {{- if .Values.dnsPolicy }} + dnsPolicy: "{{ .Values.dnsPolicy }}" + {{- end }} + {{- if .Values.hostNetwork }} + hostNetwork: {{ .Values.hostNetwork }} + {{- end }} + {{- with .Values.initContainers }} + initContainers: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: {{ template "cluster-autoscaler.name" . }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + command: + - ./cluster-autoscaler + - --cloud-provider={{ .Values.cloudProvider }} + {{- if and (eq .Values.cloudProvider "clusterapi") (eq .Values.clusterAPIMode "kubeconfig-incluster") }} + - --namespace={{ .Values.clusterAPIConfigMapsNamespace | default "kube-system" }} + {{- else }} + - --namespace={{ .Release.Namespace }} + {{- end }} + {{- if .Values.autoscalingGroups }} + {{- range .Values.autoscalingGroups }} + {{- if eq $.Values.cloudProvider "hetzner" }} + - --nodes={{ .minSize }}:{{ .maxSize }}:{{ .instanceType }}:{{ .region }}:{{ .name }} + {{- else }} + - --nodes={{ .minSize }}:{{ .maxSize }}:{{ .name }} + {{- end }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "rancher" }} + {{- if .Values.cloudConfigPath }} + - --cloud-config={{ .Values.cloudConfigPath }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "aws" }} + {{- if .Values.autoDiscovery.clusterName }} + - --node-group-auto-discovery=asg:tag={{ tpl (join "," .Values.autoDiscovery.tags) . }} + {{- end }} + {{- if .Values.cloudConfigPath }} + - --cloud-config={{ .Values.cloudConfigPath }} + {{- end }} + {{- else if eq .Values.cloudProvider "gce" }} + {{- if .Values.autoscalingGroupsnamePrefix }} + {{- range .Values.autoscalingGroupsnamePrefix }} + - --node-group-auto-discovery=mig:namePrefix={{ .name }},min={{ .minSize }},max={{ .maxSize }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "oci" }} + {{- if .Values.cloudConfigPath }} + - --nodes={{ .minSize }}:{{ .maxSize }}:{{ .name }} + - --balance-similar-node-groups + {{- end }} + {{- end }} + {{- else if eq .Values.cloudProvider "magnum" }} + {{- if .Values.autoDiscovery.clusterName }} + - --cluster-name={{ tpl (.Values.autoDiscovery.clusterName) . }} + - --node-group-auto-discovery=magnum:role={{ tpl (join "," .Values.autoDiscovery.roles) . }} + {{- else }} + - --cluster-name={{ tpl (.Values.magnumClusterName) . }} + {{- end }} + {{- else if eq .Values.cloudProvider "clusterapi" }} + {{- if or .Values.autoDiscovery.clusterName .Values.autoDiscovery.labels .Values.autoDiscovery.namespace }} + - --node-group-auto-discovery=clusterapi:{{ template "cluster-autoscaler.capiAutodiscoveryConfig" . }} + {{- end }} + {{- if eq .Values.clusterAPIMode "incluster-kubeconfig"}} + - --cloud-config={{ .Values.clusterAPICloudConfigPath }} + {{- else if eq .Values.clusterAPIMode "kubeconfig-incluster"}} + - --kubeconfig={{ .Values.clusterAPIWorkloadKubeconfigPath }} + - --clusterapi-cloud-config-authoritative + {{- else if eq .Values.clusterAPIMode "kubeconfig-kubeconfig"}} + - --kubeconfig={{ .Values.clusterAPIWorkloadKubeconfigPath }} + - --cloud-config={{ .Values.clusterAPICloudConfigPath }} + {{- else if eq .Values.clusterAPIMode "single-kubeconfig"}} + - --kubeconfig={{ .Values.clusterAPIWorkloadKubeconfigPath }} + {{- end }} + {{- else if eq .Values.cloudProvider "azure" }} + {{- if .Values.autoDiscovery.clusterName }} + - --node-group-auto-discovery=label:cluster-autoscaler-enabled=true,cluster-autoscaler-name={{ tpl (.Values.autoDiscovery.clusterName) . }} + {{- end }} + {{- end }} + {{- if eq .Values.cloudProvider "magnum" }} + - --cloud-config={{ .Values.cloudConfigPath }} + {{- end }} + {{- range $key, $value := .Values.extraArgs }} + {{- if not (kindIs "invalid" $value) }} + - --{{ $key | mustRegexFind "^[^_]+" }}={{ $value }} + {{- else }} + - --{{ $key | mustRegexFind "^[^_]+" }} + {{- end }} + {{- end }} + {{- range .Values.customArgs }} + - {{ . }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: SERVICE_ACCOUNT + valueFrom: + fieldRef: + fieldPath: spec.serviceAccountName + {{- if and (eq .Values.cloudProvider "aws") (ne .Values.awsRegion "") }} + - name: AWS_REGION + value: "{{ .Values.awsRegion }}" + {{- if .Values.awsAccessKeyID }} + - name: AWS_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + key: AwsAccessKeyId + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- if .Values.awsSecretAccessKey }} + - name: AWS_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + key: AwsSecretAccessKey + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- else if eq .Values.cloudProvider "azure" }} + - name: ARM_SUBSCRIPTION_ID + valueFrom: + secretKeyRef: + key: SubscriptionID + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_RESOURCE_GROUP + valueFrom: + secretKeyRef: + key: ResourceGroup + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_VM_TYPE + valueFrom: + secretKeyRef: + key: VMType + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: AZURE_ENABLE_FORCE_DELETE + value: "{{ .Values.azureEnableForceDelete }}" + {{- if .Values.azureUseWorkloadIdentityExtension }} + - name: ARM_USE_WORKLOAD_IDENTITY_EXTENSION + value: "true" + {{- else if .Values.azureUseManagedIdentityExtension }} + - name: ARM_USE_MANAGED_IDENTITY_EXTENSION + value: "true" + - name: ARM_USER_ASSIGNED_IDENTITY_ID + valueFrom: + secretKeyRef: + key: UserAssignedIdentityID + name: {{ template "cluster-autoscaler.fullname" . }} + {{- else }} + - name: ARM_TENANT_ID + valueFrom: + secretKeyRef: + key: TenantID + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_CLIENT_ID + valueFrom: + secretKeyRef: + key: ClientID + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: ARM_CLIENT_SECRET + valueFrom: + secretKeyRef: + key: ClientSecret + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- else if eq .Values.cloudProvider "exoscale" }} + - name: EXOSCALE_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: EXOSCALE_API_SECRET + valueFrom: + secretKeyRef: + key: api-secret + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: EXOSCALE_ZONE + valueFrom: + secretKeyRef: + key: api-zone + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- else if eq .Values.cloudProvider "kwok" }} + - name: KWOK_PROVIDER_CONFIGMAP + value: "{{.Values.kwokConfigMapName | default "kwok-provider-config"}}" + {{- else if eq .Values.cloudProvider "civo" }} + - name: CIVO_API_URL + valueFrom: + secretKeyRef: + key: api-url + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: CIVO_API_KEY + valueFrom: + secretKeyRef: + key: api-key + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: CIVO_CLUSTER_ID + valueFrom: + secretKeyRef: + key: cluster-id + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + - name: CIVO_REGION + valueFrom: + secretKeyRef: + key: region + name: {{ default (include "cluster-autoscaler.fullname" .) .Values.secretKeyRefNameOverride }} + {{- end }} + {{- range $key, $value := .Values.extraEnv }} + - name: {{ $key }} + value: "{{ $value }}" + {{- end }} + {{- range $key, $value := .Values.extraEnvConfigMaps }} + - name: {{ $key }} + valueFrom: + configMapKeyRef: + name: {{ default (include "cluster-autoscaler.fullname" $) $value.name }} + key: {{ required "Must specify key!" $value.key }} + {{- end }} + {{- range $key, $value := .Values.extraEnvSecrets }} + - name: {{ $key }} + valueFrom: + secretKeyRef: + name: {{ default (include "cluster-autoscaler.fullname" $) $value.name }} + key: {{ required "Must specify key!" $value.key }} + {{- end }} + {{- if or .Values.envFromSecret .Values.envFromConfigMap }} + envFrom: + {{- if .Values.envFromSecret }} + - secretRef: + name: {{ .Values.envFromSecret }} + {{- end }} + {{- if .Values.envFromConfigMap }} + - configMapRef: + name: {{ .Values.envFromConfigMap }} + {{- end }} + {{- end }} + livenessProbe: + httpGet: + path: /health-check + port: 8085 + ports: + - containerPort: 8085 + resources: +{{ toYaml .Values.resources | indent 12 }} + {{- if .Values.containerSecurityContext }} + securityContext: + {{ toYaml .Values.containerSecurityContext | nindent 12 | trim }} + {{- end }} + {{- if or (eq .Values.cloudProvider "magnum") .Values.extraVolumeSecrets .Values.extraVolumeMounts .Values.clusterAPIKubeconfigSecret }} + volumeMounts: + {{- if eq .Values.cloudProvider "magnum" }} + - name: cloudconfig + mountPath: {{ .Values.cloudConfigPath }} + readOnly: true + {{- end }} + {{- if and (eq .Values.cloudProvider "magnum") (.Values.magnumCABundlePath) }} + - name: ca-bundle + mountPath: {{ .Values.magnumCABundlePath }} + readOnly: true + {{- end }} + {{- range $key, $value := .Values.extraVolumeSecrets }} + - name: {{ $key }} + mountPath: {{ required "Must specify mountPath!" $value.mountPath }} + readOnly: true + {{- end }} + {{- if .Values.clusterAPIKubeconfigSecret }} + - name: cluster-api-kubeconfig + mountPath: {{ .Values.clusterAPIWorkloadKubeconfigPath | trimSuffix "/value" }} + {{- end }} + {{- if .Values.extraVolumeMounts }} + {{- toYaml .Values.extraVolumeMounts | nindent 12 }} + {{- end }} + {{- end }} + {{- if .Values.affinity }} + affinity: +{{ toYaml .Values.affinity | indent 8 }} + {{- end }} + {{- if .Values.nodeSelector }} + nodeSelector: +{{ toYaml .Values.nodeSelector | indent 8 }} + {{- end }} + serviceAccountName: {{ template "cluster-autoscaler.serviceAccountName" . }} + tolerations: +{{ toYaml .Values.tolerations | indent 8 }} + {{- if .Values.topologySpreadConstraints }} + topologySpreadConstraints: +{{ toYaml .Values.topologySpreadConstraints | indent 8 }} + {{- end }} + {{- if .Values.securityContext }} + securityContext: + {{ toYaml .Values.securityContext | nindent 8 | trim }} + {{- end }} + {{- if or (eq .Values.cloudProvider "magnum") .Values.extraVolumeSecrets .Values.extraVolumes .Values.clusterAPIKubeconfigSecret }} + volumes: + {{- if eq .Values.cloudProvider "magnum" }} + - name: cloudconfig + hostPath: + path: {{ .Values.cloudConfigPath }} + {{- end }} + {{- if and (eq .Values.cloudProvider "magnum") (.Values.magnumCABundlePath) }} + - name: ca-bundle + hostPath: + path: {{ .Values.magnumCABundlePath }} + {{- end }} + {{- range $key, $value := .Values.extraVolumeSecrets }} + - name: {{ $key }} + secret: + secretName: {{ default (include "cluster-autoscaler.fullname" $) $value.name }} + {{- if $value.items }} + items: + {{- toYaml $value.items | nindent 14 }} + {{- end }} + {{- end }} + {{- if .Values.extraVolumes }} + {{- toYaml .Values.extraVolumes | nindent 8 }} + {{- end }} + {{- if .Values.clusterAPIKubeconfigSecret }} + - name: cluster-api-kubeconfig + secret: + secretName: {{ .Values.clusterAPIKubeconfigSecret }} + {{- end }} + {{- end }} + {{- if .Values.image.pullSecrets }} + imagePullSecrets: + {{- range .Values.image.pullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/extra-manifests.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/extra-manifests.yaml new file mode 100644 index 000000000..a9bb3b6ba --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraObjects }} +--- +{{ tpl (toYaml .) $ }} +{{ end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/pdb.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/pdb.yaml new file mode 100644 index 000000000..8ad782096 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/pdb.yaml @@ -0,0 +1,16 @@ +{{- if .Values.podDisruptionBudget -}} +apiVersion: {{ template "podDisruptionBudget.apiVersion" . }} +kind: PodDisruptionBudget +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + selector: + matchLabels: +{{ include "cluster-autoscaler.instance-name" . | indent 6 }} +{{- if .Values.podDisruptionBudget }} + {{ toYaml .Values.podDisruptionBudget | nindent 2 }} +{{- end }} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml new file mode 100644 index 000000000..e3ce59973 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/podsecuritypolicy.yaml @@ -0,0 +1,42 @@ +{{- if .Values.rbac.pspEnabled }} +apiVersion: {{ template "podsecuritypolicy.apiVersion" . }} +kind: PodSecurityPolicy +metadata: + name: {{ template "cluster-autoscaler.fullname" . }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} +spec: + # Prevents running in privileged mode + privileged: false + # Required to prevent escalations to root. + allowPrivilegeEscalation: false + requiredDropCapabilities: + - ALL + volumes: + - 'configMap' + - 'secret' + - 'hostPath' + - 'emptyDir' + - 'projected' + - 'downwardAPI' + hostNetwork: {{ .Values.hostNetwork }} + hostIPC: false + hostPID: false + runAsUser: + rule: RunAsAny + seLinux: + rule: RunAsAny + supplementalGroups: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + fsGroup: + rule: 'MustRunAs' + ranges: + # Forbid adding the root group. + - min: 1 + max: 65535 + readOnlyRootFilesystem: false +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml new file mode 100644 index 000000000..8259f14ff --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/priority-expander-configmap.yaml @@ -0,0 +1,25 @@ +{{- if hasKey .Values.extraArgs "expander" }} +{{- if and (.Values.expanderPriorities) (include "cluster-autoscaler.priorityExpanderEnabled" .) -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: cluster-autoscaler-priority-expander + namespace: {{ .Release.Namespace }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + {{- if .Values.priorityConfigMapAnnotations }} + annotations: +{{ toYaml .Values.priorityConfigMapAnnotations | indent 4 }} + {{- end }} +data: + priorities: |- +{{- if kindIs "string" .Values.expanderPriorities }} +{{ .Values.expanderPriorities | indent 4 }} +{{- else }} +{{- range $k,$v := .Values.expanderPriorities }} + {{ $k | int }}: + {{- toYaml $v | nindent 6 }} +{{- end -}} +{{- end -}} +{{- end -}} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/prometheusrule.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/prometheusrule.yaml new file mode 100644 index 000000000..097c969ef --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/prometheusrule.yaml @@ -0,0 +1,15 @@ +{{- if .Values.prometheusRule.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: {{ include "cluster-autoscaler.fullname" . }} + {{- if .Values.prometheusRule.namespace }} + namespace: {{ .Values.prometheusRule.namespace }} + {{- end }} + labels: {{- toYaml .Values.prometheusRule.additionalLabels | nindent 4 }} +spec: + groups: + - name: {{ include "cluster-autoscaler.fullname" . }} + interval: {{ .Values.prometheusRule.interval }} + rules: {{- tpl (toYaml .Values.prometheusRule.rules) . | nindent 8 }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/role.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/role.yaml new file mode 100644 index 000000000..44b1678af --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/role.yaml @@ -0,0 +1,87 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - create +{{- if (include "cluster-autoscaler.priorityExpanderEnabled" .) }} + - list + - watch +{{- end }} + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - cluster-autoscaler-status +{{- if (include "cluster-autoscaler.priorityExpanderEnabled" .) }} + - cluster-autoscaler-priority-expander +{{- end }} + verbs: + - delete + - get + - update +{{- if (include "cluster-autoscaler.priorityExpanderEnabled" .) }} + - watch +{{- end }} +{{- if eq (default "" (index .Values.extraArgs "leader-elect-resource-lock")) "configmaps" }} + - apiGroups: + - "" + resources: + - configmaps + resourceNames: + - cluster-autoscaler + verbs: + - get + - update +{{- end }} +{{- if and ( and ( eq .Values.cloudProvider "clusterapi" ) ( not .Values.rbac.clusterScoped ) ( or ( eq .Values.clusterAPIMode "incluster-incluster" ) ( eq .Values.clusterAPIMode "kubeconfig-incluster" ) ))}} + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments + - machinepools + - machines + - machinesets + verbs: + - get + - list + - update + - watch + - apiGroups: + - cluster.x-k8s.io + resources: + - machinedeployments/scale + - machinepools/scale + verbs: + - get + - patch + - update +{{- end }} +{{- if ( not .Values.rbac.clusterScoped ) }} + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - apiGroups: + - coordination.k8s.io + resourceNames: + - cluster-autoscaler + resources: + - leases + verbs: + - get + - update +{{- end }} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/rolebinding.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/rolebinding.yaml new file mode 100644 index 000000000..ba5f03755 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/rolebinding.yaml @@ -0,0 +1,17 @@ +{{- if .Values.rbac.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ template "cluster-autoscaler.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ template "cluster-autoscaler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/secret.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/secret.yaml new file mode 100644 index 000000000..760cc3c5a --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/secret.yaml @@ -0,0 +1,32 @@ +{{- if not .Values.secretKeyRefNameOverride }} +{{- $isAzure := eq .Values.cloudProvider "azure" }} +{{- $isAws := eq .Values.cloudProvider "aws" }} +{{- $awsCredentialsProvided := and .Values.awsAccessKeyID .Values.awsSecretAccessKey }} +{{- $isCivo := eq .Values.cloudProvider "civo" }} + +{{- if or $isAzure (and $isAws $awsCredentialsProvided) $isCivo }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +data: +{{- if $isAzure }} + ClientID: "{{ .Values.azureClientID | b64enc }}" + ClientSecret: "{{ .Values.azureClientSecret | b64enc }}" + ResourceGroup: "{{ .Values.azureResourceGroup | b64enc }}" + SubscriptionID: "{{ .Values.azureSubscriptionID | b64enc }}" + TenantID: "{{ .Values.azureTenantID | b64enc }}" + VMType: "{{ .Values.azureVMType | b64enc }}" + UserAssignedIdentityID: "{{ .Values.azureUserAssignedIdentityID | b64enc }}" +{{- else if $isAws }} + AwsAccessKeyId: "{{ .Values.awsAccessKeyID | b64enc }}" + AwsSecretAccessKey: "{{ .Values.awsSecretAccessKey | b64enc }}" +{{- else if $isCivo }} + api-url: "{{ .Values.civoApiUrl | b64enc }}" + api-key: "{{ .Values.civoApiKey | b64enc }}" + cluster-id: "{{ .Values.civoClusterID | b64enc }}" + region: "{{ .Values.civoRegion | b64enc }}" +{{- end }} +{{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/service.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/service.yaml new file mode 100644 index 000000000..255aea44b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/service.yaml @@ -0,0 +1,39 @@ +{{- if .Values.service.create }} +apiVersion: v1 +kind: Service +metadata: +{{- if .Values.service.annotations }} + annotations: +{{ toYaml .Values.service.annotations | indent 4 }} +{{- end }} + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} +{{- if .Values.service.labels }} +{{ toYaml .Values.service.labels | indent 4 }} +{{- end }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: +{{- if .Values.service.clusterIP }} + clusterIP: "{{ .Values.service.clusterIP }}" +{{- end }} +{{- if .Values.service.externalIPs }} + externalIPs: +{{ toYaml .Values.service.externalIPs | indent 4 }} +{{- end }} +{{- if .Values.service.loadBalancerIP }} + loadBalancerIP: "{{ .Values.service.loadBalancerIP }}" +{{- end }} +{{- if .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: +{{ toYaml .Values.service.loadBalancerSourceRanges | indent 4 }} +{{- end }} + ports: + - port: {{ .Values.service.servicePort }} + protocol: TCP + targetPort: 8085 + name: {{ .Values.service.portName }} + selector: +{{ include "cluster-autoscaler.instance-name" . | indent 4 }} + type: "{{ .Values.service.type }}" +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/serviceaccount.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/serviceaccount.yaml new file mode 100644 index 000000000..29c2580c2 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if and .Values.rbac.create .Values.rbac.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- if .Values.rbac.serviceAccount.annotations }} + annotations: {{ toYaml .Values.rbac.serviceAccount.annotations | nindent 4 }} +{{- end }} +automountServiceAccountToken: {{ .Values.rbac.serviceAccount.automountServiceAccountToken }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/servicemonitor.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/servicemonitor.yaml new file mode 100644 index 000000000..9ce83a2ef --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/servicemonitor.yaml @@ -0,0 +1,36 @@ +{{ if .Values.serviceMonitor.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "cluster-autoscaler.fullname" . }} + {{- if .Values.serviceMonitor.namespace }} + namespace: {{ .Values.serviceMonitor.namespace }} + {{- end }} + {{- if .Values.serviceMonitor.annotations }} + annotations: +{{ toYaml .Values.serviceMonitor.annotations | indent 4 }} + {{- end }} + labels: + {{- range $key, $value := .Values.serviceMonitor.selector }} + {{ $key }}: {{ $value | quote }} + {{- end }} +spec: + selector: + matchLabels: +{{ include "cluster-autoscaler.instance-name" . | indent 6 }} + endpoints: + - port: {{ .Values.service.portName }} + interval: {{ .Values.serviceMonitor.interval }} + path: {{ .Values.serviceMonitor.path }} + {{- if .Values.serviceMonitor.relabelings }} + relabelings: +{{ tpl (toYaml .Values.serviceMonitor.relabelings | indent 6) . }} + {{- end }} + {{- if .Values.serviceMonitor.metricRelabelings }} + metricRelabelings: +{{ tpl (toYaml .Values.serviceMonitor.metricRelabelings | indent 6) . }} + {{- end }} + namespaceSelector: + matchNames: + - {{.Release.Namespace}} +{{ end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/vpa.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/vpa.yaml new file mode 100644 index 000000000..b889beac9 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/templates/vpa.yaml @@ -0,0 +1,20 @@ +{{- if .Values.vpa.enabled -}} +apiVersion: autoscaling.k8s.io/v1 +kind: VerticalPodAutoscaler +metadata: + labels: +{{ include "cluster-autoscaler.labels" . | indent 4 }} + name: {{ template "cluster-autoscaler.fullname" . }} + namespace: {{ .Release.Namespace }} +spec: + targetRef: + apiVersion: {{ template "deployment.apiVersion" . }} + kind: Deployment + name: {{ template "cluster-autoscaler.fullname" . }} + updatePolicy: + updateMode: {{ .Values.vpa.updateMode | quote }} + resourcePolicy: + containerPolicies: + - containerName: {{ template "cluster-autoscaler.name" . }} + {{- .Values.vpa.containerPolicy | toYaml | nindent 6 }} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/values.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/values.yaml new file mode 100644 index 000000000..663f4f65e --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/cluster-autoscaler/values.yaml @@ -0,0 +1,470 @@ +## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity +# affinity -- Affinity for pod assignment +affinity: {} + +# additionalLabels -- Labels to add to each object of the chart. +additionalLabels: {} + +autoDiscovery: + # cloudProviders `aws`, `gce`, `azure`, `magnum`, `clusterapi` and `oci` are supported by auto-discovery at this time + # AWS: Set tags as described in https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup + + # autoDiscovery.clusterName -- Enable autodiscovery for `cloudProvider=aws`, for groups matching `autoDiscovery.tags`. + # autoDiscovery.clusterName -- Enable autodiscovery for `cloudProvider=azure`, using tags defined in https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/azure/README.md#auto-discovery-setup. + # Enable autodiscovery for `cloudProvider=clusterapi`, for groups matching `autoDiscovery.labels`. + # Enable autodiscovery for `cloudProvider=gce`, but no MIG tagging required. + # Enable autodiscovery for `cloudProvider=magnum`, for groups matching `autoDiscovery.roles`. + clusterName: # cluster.local + + # autoDiscovery.namespace -- Enable autodiscovery via cluster namespace for for `cloudProvider=clusterapi` + namespace: # default + + # autoDiscovery.tags -- ASG tags to match, run through `tpl`. + tags: + - k8s.io/cluster-autoscaler/enabled + - k8s.io/cluster-autoscaler/{{ .Values.autoDiscovery.clusterName }} + # - kubernetes.io/cluster/{{ .Values.autoDiscovery.clusterName }} + + # autoDiscovery.roles -- Magnum node group roles to match. + roles: + - worker + + # autoDiscovery.labels -- Cluster-API labels to match https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#configuring-node-group-auto-discovery + labels: [] + # - color: green + # - shape: circle +# autoscalingGroups -- For AWS, Azure AKS, Exoscale or Magnum. At least one element is required if not using `autoDiscovery`. For example: +#
+# - name: asg1
+# maxSize: 2
+# minSize: 1 +#
+# For Hetzner Cloud, the `instanceType` and `region` keys are also required. +#
+# - name: mypool
+# maxSize: 2
+# minSize: 1
+# instanceType: CPX21
+# region: FSN1 +#
+autoscalingGroups: [] +# - name: asg1 +# maxSize: 2 +# minSize: 1 +# - name: asg2 +# maxSize: 2 +# minSize: 1 + +# autoscalingGroupsnamePrefix -- For GCE. At least one element is required if not using `autoDiscovery`. For example: +#
+# - name: ig01
+# maxSize: 10
+# minSize: 0 +#
+autoscalingGroupsnamePrefix: [] +# - name: ig01 +# maxSize: 10 +# minSize: 0 +# - name: ig02 +# maxSize: 10 +# minSize: 0 + +# awsAccessKeyID -- AWS access key ID ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) +awsAccessKeyID: "" + +# awsRegion -- AWS region (required if `cloudProvider=aws`) +awsRegion: us-east-1 + +# awsSecretAccessKey -- AWS access secret key ([if AWS user keys used](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#using-aws-credentials)) +awsSecretAccessKey: "" + +# azureClientID -- Service Principal ClientID with contributor permission to Cluster and Node ResourceGroup. +# Required if `cloudProvider=azure` +azureClientID: "" + +# azureClientSecret -- Service Principal ClientSecret with contributor permission to Cluster and Node ResourceGroup. +# Required if `cloudProvider=azure` +azureClientSecret: "" + +# azureResourceGroup -- Azure resource group that the cluster is located. +# Required if `cloudProvider=azure` +azureResourceGroup: "" + +# azureSubscriptionID -- Azure subscription where the resources are located. +# Required if `cloudProvider=azure` +azureSubscriptionID: "" + +# azureTenantID -- Azure tenant where the resources are located. +# Required if `cloudProvider=azure` +azureTenantID: "" + +# azureUseManagedIdentityExtension -- Whether to use Azure's managed identity extension for credentials. If using MSI, ensure subscription ID, resource group, and azure AKS cluster name are set. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. +azureUseManagedIdentityExtension: false + +# azureUserAssignedIdentityID -- When vmss has multiple user assigned identity assigned, azureUserAssignedIdentityID specifies which identity to be used +azureUserAssignedIdentityID: "" + +# azureUseWorkloadIdentityExtension -- Whether to use Azure's workload identity extension for credentials. See the project here: https://github.com/Azure/azure-workload-identity for more details. You can only use one authentication method at a time, either azureUseWorkloadIdentityExtension or azureUseManagedIdentityExtension should be set. +azureUseWorkloadIdentityExtension: false + +# azureVMType -- Azure VM type. +azureVMType: "vmss" + +# azureEnableForceDelete -- Whether to force delete VMs or VMSS instances when scaling down. +azureEnableForceDelete: false + +# civoApiUrl -- URL for the Civo API. +# Required if `cloudProvider=civo` +civoApiUrl: "https://api.civo.com" + +# civoApiKey -- API key for the Civo API. +# Required if `cloudProvider=civo` +civoApiKey: "" + +# civoClusterID -- Cluster ID for the Civo cluster. +# Required if `cloudProvider=civo` +civoClusterID: "" + +# civoRegion -- Region for the Civo cluster. +# Required if `cloudProvider=civo` +civoRegion: "" + +# cloudConfigPath -- Configuration file for cloud provider. +cloudConfigPath: "" + +# cloudProvider -- The cloud provider where the autoscaler runs. +# Currently only `gce`, `aws`, `azure`, `magnum`, `clusterapi` and `civo` are supported. +# `aws` supported for AWS. `gce` for GCE. `azure` for Azure AKS. +# `magnum` for OpenStack Magnum, `clusterapi` for Cluster API. +# `civo` for Civo Cloud. +cloudProvider: aws + +# clusterAPICloudConfigPath -- Path to kubeconfig for connecting to Cluster API Management Cluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or incluster-kubeconfig` +clusterAPICloudConfigPath: /etc/kubernetes/mgmt-kubeconfig + +# clusterAPIConfigMapsNamespace -- Namespace on the workload cluster to store Leader election and status configmaps +clusterAPIConfigMapsNamespace: "" + +# clusterAPIKubeconfigSecret -- Secret containing kubeconfig for connecting to Cluster API managed workloadcluster +# Required if `cloudProvider=clusterapi` and `clusterAPIMode=kubeconfig-kubeconfig,kubeconfig-incluster or incluster-kubeconfig` +clusterAPIKubeconfigSecret: "" + +# clusterAPIMode -- Cluster API mode, see https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/clusterapi/README.md#connecting-cluster-autoscaler-to-cluster-api-management-and-workload-clusters +# Syntax: workloadClusterMode-ManagementClusterMode +# for `kubeconfig-kubeconfig`, `incluster-kubeconfig` and `single-kubeconfig` you always must mount the external kubeconfig using either `extraVolumeSecrets` or `extraMounts` and `extraVolumes` +# if you dont set `clusterAPIKubeconfigSecret`and thus use an in-cluster config or want to use a non capi generated kubeconfig you must do so for the workload kubeconfig as well +clusterAPIMode: incluster-incluster # incluster-incluster, incluster-kubeconfig, kubeconfig-incluster, kubeconfig-kubeconfig, single-kubeconfig + +# clusterAPIWorkloadKubeconfigPath -- Path to kubeconfig for connecting to Cluster API managed workloadcluster, only used if `clusterAPIMode=kubeconfig-kubeconfig or kubeconfig-incluster` +clusterAPIWorkloadKubeconfigPath: /etc/kubernetes/value + +# containerSecurityContext -- [Security context for container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +containerSecurityContext: {} + # allowPrivilegeEscalation: false + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + +deployment: + # deployment.annotations -- Annotations to add to the Deployment object. + annotations: {} + +# dnsPolicy -- Defaults to `ClusterFirst`. Valid values are: +# `ClusterFirstWithHostNet`, `ClusterFirst`, `Default` or `None`. +# If autoscaler does not depend on cluster DNS, recommended to set this to `Default`. +dnsPolicy: ClusterFirst + +# envFromConfigMap -- ConfigMap name to use as envFrom. +envFromConfigMap: "" + +# envFromSecret -- Secret name to use as envFrom. +envFromSecret: "" + +## Priorities Expander +# expanderPriorities -- The expanderPriorities is used if `extraArgs.expander` contains `priority` and expanderPriorities is also set with the priorities. +# If `extraArgs.expander` contains `priority`, then expanderPriorities is used to define cluster-autoscaler-priority-expander priorities. +# See: https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/expander/priority/readme.md +expanderPriorities: {} + +# extraArgs -- Additional container arguments. +# Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler +# parameters and their default values. +# Everything after the first _ will be ignored allowing the use of multi-string arguments. +extraArgs: + logtostderr: true + stderrthreshold: info + v: 4 + # write-status-configmap: true + # status-config-map-name: cluster-autoscaler-status + # leader-elect: true + # leader-elect-resource-lock: endpoints + # skip-nodes-with-local-storage: true + # expander: random + # scale-down-enabled: true + # balance-similar-node-groups: true + # min-replica-count: 0 + # scale-down-utilization-threshold: 0.5 + # scale-down-non-empty-candidates-count: 30 + # max-node-provision-time: 15m0s + # scan-interval: 10s + # scale-down-delay-after-add: 10m + # scale-down-delay-after-delete: 0s + # scale-down-delay-after-failure: 3m + # scale-down-unneeded-time: 10m + # node-deletion-delay-timeout: 2m + # node-deletion-batcher-interval: 0s + # skip-nodes-with-system-pods: true + # balancing-ignore-label_1: first-label-to-ignore + # balancing-ignore-label_2: second-label-to-ignore + +# customArgs -- Additional custom container arguments. +# Refer to https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-are-the-parameters-to-ca for the full list of cluster autoscaler +# parameters and their default values. +# List of arguments as strings. +customArgs: [] + +# extraEnv -- Additional container environment variables. +extraEnv: {} + +# extraEnvConfigMaps -- Additional container environment variables from ConfigMaps. +extraEnvConfigMaps: {} + +# extraEnvSecrets -- Additional container environment variables from Secrets. +extraEnvSecrets: {} + +# extraObjects -- Extra K8s manifests to deploy +extraObjects: [] +# - apiVersion: v1 +# kind: ConfigMap +# metadata: +# name: my-configmap +# data: +# key: "value" +# - apiVersion: scheduling.k8s.io/v1 +# kind: PriorityClass +# metadata: +# name: high-priority +# value: 1000000 +# globalDefault: false +# description: "This priority class should be used for XYZ service pods only." + +# extraVolumeMounts -- Additional volumes to mount. +extraVolumeMounts: [] + # - name: ssl-certs + # mountPath: /etc/ssl/certs/ca-certificates.crt + # readOnly: true + +# extraVolumes -- Additional volumes. +extraVolumes: [] + # - name: ssl-certs + # hostPath: + # path: /etc/ssl/certs/ca-bundle.crt + +# extraVolumeSecrets -- Additional volumes to mount from Secrets. +extraVolumeSecrets: {} + # autoscaler-vol: + # mountPath: /data/autoscaler/ + # custom-vol: + # name: custom-secret + # mountPath: /data/custom/ + # items: + # - key: subkey + # path: mypath + +# initContainers -- Any additional init containers. +initContainers: [] + +# fullnameOverride -- String to fully override `cluster-autoscaler.fullname` template. +fullnameOverride: "" + +# hostNetwork -- Whether to expose network interfaces of the host machine to pods. +hostNetwork: false + +image: + # image.repository -- Image repository + repository: registry.k8s.io/autoscaling/cluster-autoscaler + # image.tag -- Image tag + tag: v1.32.0 + # image.pullPolicy -- Image pull policy + pullPolicy: IfNotPresent + ## Optionally specify an array of imagePullSecrets. + ## Secrets must be manually created in the namespace. + ## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/ + ## + # image.pullSecrets -- Image pull secrets + pullSecrets: [] + # - myRegistrKeySecretName + +# kubeTargetVersionOverride -- Allow overriding the `.Capabilities.KubeVersion.GitVersion` check. Useful for `helm template` commands. +kubeTargetVersionOverride: "" + +# kwokConfigMapName -- configmap for configuring kwok provider +kwokConfigMapName: "kwok-provider-config" + +# magnumCABundlePath -- Path to the host's CA bundle, from `ca-file` in the cloud-config file. +magnumCABundlePath: "/etc/kubernetes/ca-bundle.crt" + +# magnumClusterName -- Cluster name or ID in Magnum. +# Required if `cloudProvider=magnum` and not setting `autoDiscovery.clusterName`. +magnumClusterName: "" + +# nameOverride -- String to partially override `cluster-autoscaler.fullname` template (will maintain the release name) +nameOverride: "" + +# nodeSelector -- Node labels for pod assignment. Ref: https://kubernetes.io/docs/user-guide/node-selection/. +nodeSelector: {} + +# podAnnotations -- Annotations to add to each pod. +podAnnotations: {} + +# podDisruptionBudget -- Pod disruption budget. +podDisruptionBudget: + maxUnavailable: 1 + # minAvailable: 2 + +# podLabels -- Labels to add to each pod. +podLabels: {} + +# priorityClassName -- priorityClassName +priorityClassName: "system-cluster-critical" + +# priorityConfigMapAnnotations -- Annotations to add to `cluster-autoscaler-priority-expander` ConfigMap. +priorityConfigMapAnnotations: {} + # key1: "value1" + # key2: "value2" + +## Custom PrometheusRule to be defined +## The value is evaluated as a template, so, for example, the value can depend on .Release or .Chart +## ref: https://github.com/coreos/prometheus-operator#customresourcedefinitions +prometheusRule: + # prometheusRule.enabled -- If true, creates a Prometheus Operator PrometheusRule. + enabled: false + # prometheusRule.additionalLabels -- Additional labels to be set in metadata. + additionalLabels: {} + # prometheusRule.namespace -- Namespace which Prometheus is running in. + namespace: monitoring + # prometheusRule.interval -- How often rules in the group are evaluated (falls back to `global.evaluation_interval` if not set). + interval: null + # prometheusRule.rules -- Rules spec template (see https://github.com/prometheus-operator/prometheus-operator/blob/master/Documentation/api.md#rule). + rules: [] + +rbac: + # rbac.create -- If `true`, create and use RBAC resources. + create: true + # rbac.pspEnabled -- If `true`, creates and uses RBAC resources required in the cluster with [Pod Security Policies](https://kubernetes.io/docs/concepts/policy/pod-security-policy/) enabled. + # Must be used with `rbac.create` set to `true`. + pspEnabled: false + # rbac.clusterScoped -- if set to false will only provision RBAC to alter resources in the current namespace. Most useful for Cluster-API + clusterScoped: true + serviceAccount: + # rbac.serviceAccount.annotations -- Additional Service Account annotations. + annotations: {} + # rbac.serviceAccount.create -- If `true` and `rbac.create` is also true, a Service Account will be created. + create: true + # rbac.serviceAccount.name -- The name of the ServiceAccount to use. If not set and create is `true`, a name is generated using the fullname template. + name: "" + # rbac.serviceAccount.automountServiceAccountToken -- Automount API credentials for a Service Account. + automountServiceAccountToken: true + +# replicaCount -- Desired number of pods +replicaCount: 1 + +# resources -- Pod resource requests and limits. +resources: {} + # limits: + # cpu: 100m + # memory: 300Mi + # requests: + # cpu: 100m + # memory: 300Mi + +# revisionHistoryLimit -- The number of revisions to keep. +revisionHistoryLimit: 10 + +# securityContext -- [Security context for pod](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/) +securityContext: {} + # runAsNonRoot: true + # runAsUser: 65534 + # runAsGroup: 65534 + # seccompProfile: + # type: RuntimeDefault + +service: + # service.create -- If `true`, a Service will be created. + create: true + # service.annotations -- Annotations to add to service + annotations: {} + # service.labels -- Labels to add to service + labels: {} + # service.externalIPs -- List of IP addresses at which the service is available. Ref: https://kubernetes.io/docs/concepts/services-networking/service/#external-ips. + externalIPs: [] + + # service.clusterIP -- IP address to assign to service + clusterIP: "" + + # service.loadBalancerIP -- IP address to assign to load balancer (if supported). + loadBalancerIP: "" + # service.loadBalancerSourceRanges -- List of IP CIDRs allowed access to load balancer (if supported). + loadBalancerSourceRanges: [] + # service.servicePort -- Service port to expose. + servicePort: 8085 + # service.portName -- Name for service port. + portName: http + # service.type -- Type of service to create. + type: ClusterIP + +## Are you using Prometheus Operator? +serviceMonitor: + # serviceMonitor.enabled -- If true, creates a Prometheus Operator ServiceMonitor. + enabled: false + # serviceMonitor.interval -- Interval that Prometheus scrapes Cluster Autoscaler metrics. + interval: 10s + # serviceMonitor.namespace -- Namespace which Prometheus is running in. + namespace: monitoring + ## [Prometheus Selector Label](https://github.com/helm/charts/tree/master/stable/prometheus-operator#prometheus-operator-1) + ## [Kube Prometheus Selector Label](https://github.com/helm/charts/tree/master/stable/prometheus-operator#exporters) + # serviceMonitor.selector -- Default to kube-prometheus install (CoreOS recommended), but should be set according to Prometheus install. + selector: + release: prometheus-operator + # serviceMonitor.path -- The path to scrape for metrics; autoscaler exposes `/metrics` (this is standard) + path: /metrics + # serviceMonitor.annotations -- Annotations to add to service monitor + annotations: {} + ## [RelabelConfig](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.RelabelConfig) + # serviceMonitor.relabelings -- RelabelConfigs to apply to metrics before scraping. + relabelings: {} + ## [RelabelConfig](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#monitoring.coreos.com/v1.RelabelConfig) + # serviceMonitor.metricRelabelings -- MetricRelabelConfigs to apply to samples before ingestion. + metricRelabelings: {} + +# tolerations -- List of node taints to tolerate (requires Kubernetes >= 1.6). +tolerations: [] + +# topologySpreadConstraints -- You can use topology spread constraints to control how Pods are spread across your cluster among failure-domains such as regions, zones, nodes, and other user-defined topology domains. (requires Kubernetes >= 1.19). +topologySpreadConstraints: [] + # - maxSkew: 1 + # topologyKey: topology.kubernetes.io/zone + # whenUnsatisfiable: DoNotSchedule + # labelSelector: + # matchLabels: + # app.kubernetes.io/instance: cluster-autoscaler + +# updateStrategy -- [Deployment update strategy](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy) +updateStrategy: {} + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 0 + # type: RollingUpdate + +# vpa -- Configure a VerticalPodAutoscaler for the cluster-autoscaler Deployment. +vpa: + # vpa.enabled -- If true, creates a VerticalPodAutoscaler. + enabled: false + # vpa.updateMode -- [UpdateMode](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L124) + updateMode: "Auto" + # vpa.containerPolicy -- [ContainerResourcePolicy](https://github.com/kubernetes/autoscaler/blob/vertical-pod-autoscaler/v0.13.0/vertical-pod-autoscaler/pkg/apis/autoscaling.k8s.io/v1/types.go#L159). The containerName is always et to the deployment's container name. This value is required if VPA is enabled. + containerPolicy: {} + +# secretKeyRefNameOverride -- Overrides the name of the Secret to use when loading the secretKeyRef for AWS, Azure and Civo env variables +secretKeyRefNameOverride: "" diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/.helmignore b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/.helmignore new file mode 100644 index 000000000..50af03172 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/Chart.yaml new file mode 100644 index 000000000..269a870c9 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/Chart.yaml @@ -0,0 +1,23 @@ +apiVersion: v2 +appVersion: v24.9.2 +dependencies: +- condition: nfd.enabled + name: node-feature-discovery + repository: https://kubernetes-sigs.github.io/node-feature-discovery/charts + version: v0.16.6 +description: NVIDIA GPU Operator creates/configures/manages GPUs atop Kubernetes +home: https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/overview.html +icon: https://assets.nvidiagrid.net/ngc/logos/GPUoperator.png +keywords: +- gpu +- cuda +- compute +- operator +- deep learning +- monitoring +- tesla +kubeVersion: '>= 1.16.0-0' +name: gpu-operator +sources: +- https://github.com/NVIDIA/gpu-operator +version: v24.9.2 diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/.helmignore b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/.helmignore new file mode 100644 index 000000000..0e8a0eb36 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/Chart.yaml new file mode 100644 index 000000000..7656c732f --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +appVersion: v0.16.6 +description: 'Detects hardware features available on each node in a Kubernetes cluster, + and advertises those features using node labels. ' +home: https://github.com/kubernetes-sigs/node-feature-discovery +keywords: +- feature-discovery +- feature-detection +- node-labels +name: node-feature-discovery +sources: +- https://github.com/kubernetes-sigs/node-feature-discovery +type: application +version: 0.16.6 diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/README.md b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/README.md new file mode 100644 index 000000000..93734f8b7 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/README.md @@ -0,0 +1,10 @@ +# Node Feature Discovery + +Node Feature Discovery (NFD) is a Kubernetes add-on for detecting hardware +features and system configuration. Detected features are advertised as node +labels. NFD provides flexible configuration and extension points for a wide +range of vendor and application specific node labeling needs. + +See +[NFD documentation](https://kubernetes-sigs.github.io/node-feature-discovery/v0.16/deployment/helm.html) +for deployment instructions. diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/crds/nfd-api-crds.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/crds/nfd-api-crds.yaml new file mode 100644 index 000000000..0a73c5dca --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/crds/nfd-api-crds.yaml @@ -0,0 +1,710 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: nodefeatures.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeature + listKind: NodeFeatureList + plural: nodefeatures + singular: nodefeature + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + NodeFeature resource holds the features discovered for one node in the + cluster. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of the NodeFeature, containing features discovered + for a node. + properties: + features: + description: Features is the full "raw" features data that has been + discovered. + properties: + attributes: + additionalProperties: + description: AttributeFeatureSet is a set of features having + string value. + properties: + elements: + additionalProperties: + type: string + description: Individual features of the feature set. + type: object + required: + - elements + type: object + description: Attributes contains all the attribute-type features + of the node. + type: object + flags: + additionalProperties: + description: FlagFeatureSet is a set of simple features only + containing names without values. + properties: + elements: + additionalProperties: + description: Nil is a dummy empty struct for protobuf + compatibility + type: object + description: Individual features of the feature set. + type: object + required: + - elements + type: object + description: Flags contains all the flag-type features of the + node. + type: object + instances: + additionalProperties: + description: InstanceFeatureSet is a set of features each of + which is an instance having multiple attributes. + properties: + elements: + description: Individual features of the feature set. + items: + description: InstanceFeature represents one instance of + a complex features, e.g. a device. + properties: + attributes: + additionalProperties: + type: string + description: Attributes of the instance feature. + type: object + required: + - attributes + type: object + type: array + required: + - elements + type: object + description: Instances contains all the instance-type features + of the node. + type: object + type: object + labels: + additionalProperties: + type: string + description: Labels is the set of node labels that are requested to + be created. + type: object + type: object + required: + - spec + type: object + served: true + storage: true +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: nodefeaturegroups.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureGroup + listKind: NodeFeatureGroupList + plural: nodefeaturegroups + shortNames: + - nfg + singular: nodefeaturegroup + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeFeatureGroup resource holds Node pools by featureGroup + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the rules to be evaluated. + properties: + featureGroupRules: + description: List of rules to evaluate to determine nodes that belong + in this group. + items: + description: GroupRule defines a rule for nodegroup filtering. + properties: + matchAny: + description: MatchAny specifies a list of matchers one of which + must match. + items: + description: MatchAnyElem specifies one sub-matcher of MatchAny. + properties: + matchFeatures: + description: MatchFeatures specifies a set of matcher + terms all of which must match. + items: + description: |- + FeatureMatcherTerm defines requirements against one feature set. All + requirements (specified as MatchExpressions) are evaluated against each + element in the feature set. + properties: + feature: + description: Feature is the name of the feature + set to match against. + type: string + matchExpressions: + additionalProperties: + description: |- + MatchExpression specifies an expression to evaluate against a set of input + values. It contains an operator that is applied when matching the input and + an array of values that the operator evaluates the input against. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: |- + MatchExpressions is the set of per-element expressions evaluated. These + match against the value of the specified elements. + type: object + matchName: + description: |- + MatchName in an expression that is matched against the name of each + element in the feature set. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + required: + - feature + type: object + type: array + required: + - matchFeatures + type: object + type: array + matchFeatures: + description: MatchFeatures specifies a set of matcher terms + all of which must match. + items: + description: |- + FeatureMatcherTerm defines requirements against one feature set. All + requirements (specified as MatchExpressions) are evaluated against each + element in the feature set. + properties: + feature: + description: Feature is the name of the feature set to + match against. + type: string + matchExpressions: + additionalProperties: + description: |- + MatchExpression specifies an expression to evaluate against a set of input + values. It contains an operator that is applied when matching the input and + an array of values that the operator evaluates the input against. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: |- + MatchExpressions is the set of per-element expressions evaluated. These + match against the value of the specified elements. + type: object + matchName: + description: |- + MatchName in an expression that is matched against the name of each + element in the feature set. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + required: + - feature + type: object + type: array + name: + description: Name of the rule. + type: string + required: + - name + type: object + type: array + required: + - featureGroupRules + type: object + status: + description: |- + Status of the NodeFeatureGroup after the most recent evaluation of the + specification. + properties: + nodes: + description: Nodes is a list of FeatureGroupNode in the cluster that + match the featureGroupRules + items: + properties: + name: + description: Name of the node. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + name: nodefeaturerules.nfd.k8s-sigs.io +spec: + group: nfd.k8s-sigs.io + names: + kind: NodeFeatureRule + listKind: NodeFeatureRuleList + plural: nodefeaturerules + shortNames: + - nfr + singular: nodefeaturerule + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + NodeFeatureRule resource specifies a configuration for feature-based + customization of node objects, such as node labeling. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the rules to be evaluated. + properties: + rules: + description: Rules is a list of node customization rules. + items: + description: Rule defines a rule for node customization such as + labeling. + properties: + annotations: + additionalProperties: + type: string + description: Annotations to create if the rule matches. + type: object + extendedResources: + additionalProperties: + type: string + description: ExtendedResources to create if the rule matches. + type: object + labels: + additionalProperties: + type: string + description: Labels to create if the rule matches. + type: object + labelsTemplate: + description: |- + LabelsTemplate specifies a template to expand for dynamically generating + multiple labels. Data (after template expansion) must be keys with an + optional value ([=]) separated by newlines. + type: string + matchAny: + description: MatchAny specifies a list of matchers one of which + must match. + items: + description: MatchAnyElem specifies one sub-matcher of MatchAny. + properties: + matchFeatures: + description: MatchFeatures specifies a set of matcher + terms all of which must match. + items: + description: |- + FeatureMatcherTerm defines requirements against one feature set. All + requirements (specified as MatchExpressions) are evaluated against each + element in the feature set. + properties: + feature: + description: Feature is the name of the feature + set to match against. + type: string + matchExpressions: + additionalProperties: + description: |- + MatchExpression specifies an expression to evaluate against a set of input + values. It contains an operator that is applied when matching the input and + an array of values that the operator evaluates the input against. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: |- + MatchExpressions is the set of per-element expressions evaluated. These + match against the value of the specified elements. + type: object + matchName: + description: |- + MatchName in an expression that is matched against the name of each + element in the feature set. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + required: + - feature + type: object + type: array + required: + - matchFeatures + type: object + type: array + matchFeatures: + description: MatchFeatures specifies a set of matcher terms + all of which must match. + items: + description: |- + FeatureMatcherTerm defines requirements against one feature set. All + requirements (specified as MatchExpressions) are evaluated against each + element in the feature set. + properties: + feature: + description: Feature is the name of the feature set to + match against. + type: string + matchExpressions: + additionalProperties: + description: |- + MatchExpression specifies an expression to evaluate against a set of input + values. It contains an operator that is applied when matching the input and + an array of values that the operator evaluates the input against. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + description: |- + MatchExpressions is the set of per-element expressions evaluated. These + match against the value of the specified elements. + type: object + matchName: + description: |- + MatchName in an expression that is matched against the name of each + element in the feature set. + properties: + op: + description: Op is the operator to be applied. + enum: + - In + - NotIn + - InRegexp + - Exists + - DoesNotExist + - Gt + - Lt + - GtLt + - IsTrue + - IsFalse + type: string + value: + description: |- + Value is the list of values that the operand evaluates the input + against. Value should be empty if the operator is Exists, DoesNotExist, + IsTrue or IsFalse. Value should contain exactly one element if the + operator is Gt or Lt and exactly two elements if the operator is GtLt. + In other cases Value should contain at least one element. + items: + type: string + type: array + required: + - op + type: object + required: + - feature + type: object + type: array + name: + description: Name of the rule. + type: string + taints: + description: Taints to create if the rule matches. + items: + description: |- + The node this Taint is attached to has the "effect" on + any pod that does not tolerate the Taint. + properties: + effect: + description: |- + Required. The effect of the taint on pods + that do not tolerate the taint. + Valid effects are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: Required. The taint key to be applied to + a node. + type: string + timeAdded: + description: |- + TimeAdded represents the time at which the taint was added. + It is only written for NoExecute taints. + format: date-time + type: string + value: + description: The taint value corresponding to the taint + key. + type: string + required: + - effect + - key + type: object + type: array + vars: + additionalProperties: + type: string + description: |- + Vars is the variables to store if the rule matches. Variables do not + directly inflict any changes in the node object. However, they can be + referenced from other rules enabling more complex rule hierarchies, + without exposing intermediary output values as labels. + type: object + varsTemplate: + description: |- + VarsTemplate specifies a template to expand for dynamically generating + multiple variables. Data (after template expansion) must be keys with an + optional value ([=]) separated by newlines. + type: string + required: + - name + type: object + type: array + required: + - rules + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/_helpers.tpl b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/_helpers.tpl new file mode 100644 index 000000000..928ece78f --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/_helpers.tpl @@ -0,0 +1,107 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "node-feature-discovery.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "node-feature-discovery.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "node-feature-discovery.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "node-feature-discovery.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "node-feature-discovery.labels" -}} +helm.sh/chart: {{ include "node-feature-discovery.chart" . }} +{{ include "node-feature-discovery.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Selector labels +*/}} +{{- define "node-feature-discovery.selectorLabels" -}} +app.kubernetes.io/name: {{ include "node-feature-discovery.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end -}} + +{{/* +Create the name of the service account which the nfd master will use +*/}} +{{- define "node-feature-discovery.master.serviceAccountName" -}} +{{- if .Values.master.serviceAccount.create -}} + {{ default (include "node-feature-discovery.fullname" .) .Values.master.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.master.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account which the nfd worker will use +*/}} +{{- define "node-feature-discovery.worker.serviceAccountName" -}} +{{- if .Values.worker.serviceAccount.create -}} + {{ default (printf "%s-worker" (include "node-feature-discovery.fullname" .)) .Values.worker.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.worker.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account which topologyUpdater will use +*/}} +{{- define "node-feature-discovery.topologyUpdater.serviceAccountName" -}} +{{- if .Values.topologyUpdater.serviceAccount.create -}} + {{ default (printf "%s-topology-updater" (include "node-feature-discovery.fullname" .)) .Values.topologyUpdater.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.topologyUpdater.serviceAccount.name }} +{{- end -}} +{{- end -}} + +{{/* +Create the name of the service account which nfd-gc will use +*/}} +{{- define "node-feature-discovery.gc.serviceAccountName" -}} +{{- if .Values.gc.serviceAccount.create -}} + {{ default (printf "%s-gc" (include "node-feature-discovery.fullname" .)) .Values.gc.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.gc.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-certs.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-certs.yaml new file mode 100644 index 000000000..2d1576022 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-certs.yaml @@ -0,0 +1,80 @@ +{{- if .Values.tls.certManager }} +{{- if .Values.master.enable }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-master-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + secretName: nfd-master-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-master + dnsNames: + # must match the service name + - {{ include "node-feature-discovery.fullname" . }}-master + # first one is configured for use by the worker; below are for completeness + - {{ include "node-feature-discovery.fullname" . }}-master.{{ include "node-feature-discovery.namespace" . }}.svc + - {{ include "node-feature-discovery.fullname" . }}-master.{{ include "node-feature-discovery.namespace" . }}.svc.cluster.local + issuerRef: + name: {{ default "nfd-ca-issuer" .Values.tls.certManagerCertificate.issuerName }} + {{- if and .Values.tls.certManagerCertificate.issuerName .Values.tls.certManagerCertificate.issuerKind }} + kind: {{ .Values.tls.certManagerCertificate.issuerKind }} + {{- else }} + kind: Issuer + {{- end }} + group: cert-manager.io +{{- end }} +--- +{{- if .Values.worker.enable }} +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-worker-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + secretName: nfd-worker-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-worker + dnsNames: + - {{ include "node-feature-discovery.fullname" . }}-worker.{{ include "node-feature-discovery.namespace" . }}.svc.cluster.local + issuerRef: + name: {{ default "nfd-ca-issuer" .Values.tls.certManagerCertificate.issuerName }} + {{- if and .Values.tls.certManagerCertificate.issuerName .Values.tls.certManagerCertificate.issuerKind }} + kind: {{ .Values.tls.certManagerCertificate.issuerKind }} + {{- else }} + kind: Issuer + {{- end }} + group: cert-manager.io +{{- end }} + +{{- if .Values.topologyUpdater.enable }} +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-topology-updater-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + secretName: nfd-topology-updater-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-topology-updater + dnsNames: + - {{ include "node-feature-discovery.fullname" . }}-topology-updater.{{ include "node-feature-discovery.namespace" . }}.svc.cluster.local + issuerRef: + name: {{ default "nfd-ca-issuer" .Values.tls.certManagerCertificate.issuerName }} + {{- if and .Values.tls.certManagerCertificate.issuerName .Values.tls.certManagerCertificate.issuerKind }} + kind: {{ .Values.tls.certManagerCertificate.issuerKind }} + {{- else }} + kind: Issuer + {{- end }} + group: cert-manager.io +{{- end }} + +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-issuer.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-issuer.yaml new file mode 100644 index 000000000..874468908 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/cert-manager-issuer.yaml @@ -0,0 +1,42 @@ +{{- if and .Values.tls.certManager (not .Values.tls.certManagerCertificate.issuerName ) }} +# See https://cert-manager.io/docs/configuration/selfsigned/#bootstrapping-ca-issuers +# - Create a self signed issuer +# - Use this to create a CA cert +# - Use this to now create a CA issuer +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: nfd-ca-bootstrap + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + selfSigned: {} + +--- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: nfd-ca-cert + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + isCA: true + secretName: nfd-ca-cert + subject: + organizations: + - node-feature-discovery + commonName: nfd-ca-cert + issuerRef: + name: nfd-ca-bootstrap + kind: Issuer + group: cert-manager.io + +--- +apiVersion: cert-manager.io/v1 +kind: Issuer +metadata: + name: nfd-ca-issuer + namespace: {{ include "node-feature-discovery.namespace" . }} +spec: + ca: + secretName: nfd-ca-cert +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrole.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrole.yaml new file mode 100644 index 000000000..f935cfe41 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrole.yaml @@ -0,0 +1,133 @@ +{{- if and .Values.master.enable .Values.master.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + - nodes/status + verbs: + - get + - patch + - update + - list +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeatures + - nodefeaturerules + - nodefeaturegroups + verbs: + - get + - list + - watch +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeaturegroups/status + verbs: + - patch + - update +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create +- apiGroups: + - coordination.k8s.io + resources: + - leases + resourceNames: + - "nfd-master.nfd.kubernetes.io" + verbs: + - get + - update +{{- end }} + +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get +- apiGroups: + - "" + resources: + - nodes/proxy + verbs: + - get +- apiGroups: + - "" + resources: + - pods + verbs: + - get +- apiGroups: + - topology.node.k8s.io + resources: + - noderesourcetopologies + verbs: + - create + - get + - update +{{- end }} + +{{- if and .Values.gc.enable .Values.gc.rbac.create (or (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi) .Values.topologyUpdater.enable) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-gc + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - "" + resources: + - nodes + verbs: + - list + - watch +- apiGroups: + - "" + resources: + - nodes/proxy + verbs: + - get +- apiGroups: + - topology.node.k8s.io + resources: + - noderesourcetopologies + verbs: + - delete + - list +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeatures + verbs: + - delete + - list +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrolebinding.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..3f717988b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/clusterrolebinding.yaml @@ -0,0 +1,52 @@ +{{- if and .Values.master.enable .Values.master.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }} +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.master.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} + +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.rbac.create }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} + +{{- if and .Values.gc.enable .Values.gc.rbac.create (or (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi) .Values.topologyUpdater.enable) }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-gc + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }}-gc +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.gc.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/master.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/master.yaml new file mode 100644 index 000000000..733131a03 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/master.yaml @@ -0,0 +1,152 @@ +{{- if .Values.master.enable }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-master + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: master + {{- with .Values.master.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.master.replicaCount }} + revisionHistoryLimit: {{ .Values.master.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: master + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: master + {{- with .Values.master.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "node-feature-discovery.master.serviceAccountName" . }} + enableServiceLinks: false + securityContext: + {{- toYaml .Values.master.podSecurityContext | nindent 8 }} + hostNetwork: {{ .Values.master.hostNetwork }} + containers: + - name: master + securityContext: + {{- toYaml .Values.master.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + {{- toYaml .Values.master.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.master.readinessProbe | nindent 12 }} + ports: + - containerPort: {{ .Values.master.port | default "8080" }} + name: grpc + - containerPort: {{ .Values.master.metricsPort | default "8081" }} + name: metrics + - containerPort: {{ .Values.master.healthPort | default "8082" }} + name: health + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + {{- with .Values.master.extraEnvs }} + {{- toYaml . | nindent 8 }} + {{- end}} + command: + - "nfd-master" + resources: + {{- toYaml .Values.master.resources | nindent 12 }} + args: + {{- if .Values.master.instance | empty | not }} + - "-instance={{ .Values.master.instance }}" + {{- end }} + {{- if not (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi) }} + - "-port={{ .Values.master.port | default "8080" }}" + {{- else if gt (int .Values.master.replicaCount) 1 }} + - "-enable-leader-election" + {{- end }} + {{- if .Values.master.extraLabelNs | empty | not }} + - "-extra-label-ns={{- join "," .Values.master.extraLabelNs }}" + {{- end }} + {{- if .Values.master.denyLabelNs | empty | not }} + - "-deny-label-ns={{- join "," .Values.master.denyLabelNs }}" + {{- end }} + {{- if .Values.master.resourceLabels | empty | not }} + - "-resource-labels={{- join "," .Values.master.resourceLabels }}" + {{- end }} + {{- if .Values.master.enableTaints }} + - "-enable-taints" + {{- end }} + {{- if .Values.master.crdController | kindIs "invalid" | not }} + - "-crd-controller={{ .Values.master.crdController }}" + {{- else }} + ## By default, disable crd controller for other than the default instances + - "-crd-controller={{ .Values.master.instance | empty }}" + {{- end }} + {{- if .Values.master.featureRulesController | kindIs "invalid" | not }} + - "-featurerules-controller={{ .Values.master.featureRulesController }}" + {{- end }} + {{- if .Values.master.resyncPeriod }} + - "-resync-period={{ .Values.master.resyncPeriod }}" + {{- end }} + {{- if .Values.master.nfdApiParallelism | empty | not }} + - "-nfd-api-parallelism={{ .Values.master.nfdApiParallelism }}" + {{- end }} + {{- if .Values.tls.enable }} + - "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" + - "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" + - "-cert-file=/etc/kubernetes/node-feature-discovery/certs/tls.crt" + {{- end }} + # Go over featureGates and add the feature-gate flag + {{- range $key, $value := .Values.featureGates }} + - "-feature-gates={{ $key }}={{ $value }}" + {{- end }} + - "-metrics={{ .Values.master.metricsPort | default "8081" }}" + - "-grpc-health={{ .Values.master.healthPort | default "8082" }}" + volumeMounts: + {{- if .Values.tls.enable }} + - name: nfd-master-cert + mountPath: "/etc/kubernetes/node-feature-discovery/certs" + readOnly: true + {{- end }} + - name: nfd-master-conf + mountPath: "/etc/kubernetes/node-feature-discovery" + readOnly: true + volumes: + {{- if .Values.tls.enable }} + - name: nfd-master-cert + secret: + secretName: nfd-master-cert + {{- end }} + - name: nfd-master-conf + configMap: + name: {{ include "node-feature-discovery.fullname" . }}-master-conf + items: + - key: nfd-master.conf + path: nfd-master.conf + {{- with .Values.master.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.master.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.master.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-gc.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-gc.yaml new file mode 100644 index 000000000..375f93827 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-gc.yaml @@ -0,0 +1,85 @@ +{{- if and .Values.gc.enable (or (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi) .Values.topologyUpdater.enable) -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-gc + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: gc + {{- with .Values.gc.deploymentAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.gc.replicaCount | default 1 }} + revisionHistoryLimit: {{ .Values.gc.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: gc + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: gc + {{- with .Values.gc.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "node-feature-discovery.gc.serviceAccountName" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.gc.podSecurityContext | nindent 8 }} + hostNetwork: {{ .Values.gc.hostNetwork }} + containers: + - name: gc + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + {{- with .Values.gc.extraEnvs }} + {{- toYaml . | nindent 8 }} + {{- end}} + command: + - "nfd-gc" + args: + {{- if .Values.gc.interval | empty | not }} + - "-gc-interval={{ .Values.gc.interval }}" + {{- end }} + resources: + {{- toYaml .Values.gc.resources | nindent 12 }} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsNonRoot: true + ports: + - name: metrics + containerPort: {{ .Values.gc.metricsPort | default "8081"}} + + {{- with .Values.gc.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.gc.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.gc.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-master-conf.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-master-conf.yaml new file mode 100644 index 000000000..9c6e01cde --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-master-conf.yaml @@ -0,0 +1,12 @@ +{{- if .Values.master.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-master-conf + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +data: + nfd-master.conf: |- + {{- .Values.master.config | toYaml | nindent 4 }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-topologyupdater-conf.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-topologyupdater-conf.yaml new file mode 100644 index 000000000..8d03aa2d8 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-topologyupdater-conf.yaml @@ -0,0 +1,12 @@ +{{- if .Values.topologyUpdater.enable -}} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater-conf + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +data: + nfd-topology-updater.conf: |- + {{- .Values.topologyUpdater.config | toYaml | nindent 4 }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-worker-conf.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-worker-conf.yaml new file mode 100644 index 000000000..a2299dea1 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/nfd-worker-conf.yaml @@ -0,0 +1,12 @@ +{{- if .Values.worker.enable }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker-conf + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +data: + nfd-worker.conf: |- + {{- .Values.worker.config | toYaml | nindent 4 }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/post-delete-job.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/post-delete-job.yaml new file mode 100644 index 000000000..4364f1aa2 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/post-delete-job.yaml @@ -0,0 +1,94 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-prune + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-prune + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +rules: +- apiGroups: + - "" + resources: + - nodes + - nodes/status + verbs: + - get + - patch + - update + - list +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-prune + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "node-feature-discovery.fullname" . }}-prune +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.fullname" . }}-prune + namespace: {{ include "node-feature-discovery.namespace" . }} +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-prune + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": post-delete + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + template: + metadata: + labels: + {{- include "node-feature-discovery.labels" . | nindent 8 }} + role: prune + spec: + serviceAccountName: {{ include "node-feature-discovery.fullname" . }}-prune + containers: + - name: nfd-master + securityContext: + {{- toYaml .Values.master.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - "nfd-master" + args: + - "-prune" + {{- if .Values.master.instance | empty | not }} + - "-instance={{ .Values.master.instance }}" + {{- end }} + restartPolicy: Never + {{- with .Values.master.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.master.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.master.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/prometheus.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/prometheus.yaml new file mode 100644 index 000000000..3d680e24e --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/prometheus.yaml @@ -0,0 +1,26 @@ +{{- if .Values.prometheus.enable }} +# Prometheus Monitor Service (Metrics) +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: {{ include "node-feature-discovery.fullname" . }} + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 4 }} + {{- with .Values.prometheus.labels }} + {{ toYaml . | nindent 4 }} + {{- end }} +spec: + podMetricsEndpoints: + - honorLabels: true + interval: {{ .Values.prometheus.scrapeInterval }} + path: /metrics + port: metrics + scheme: http + namespaceSelector: + matchNames: + - {{ include "node-feature-discovery.namespace" . }} + selector: + matchExpressions: + - {key: app.kubernetes.io/instance, operator: In, values: ["{{ .Release.Name }}"]} + - {key: app.kubernetes.io/name, operator: In, values: ["{{ include "node-feature-discovery.name" . }}"]} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/role.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/role.yaml new file mode 100644 index 000000000..52c69eb19 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/role.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.worker.enable .Values.worker.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +rules: +- apiGroups: + - nfd.k8s-sigs.io + resources: + - nodefeatures + verbs: + - create + - get + - update +- apiGroups: + - "" + resources: + - pods + verbs: + - get +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/rolebinding.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/rolebinding.yaml new file mode 100644 index 000000000..a640d5f8b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/rolebinding.yaml @@ -0,0 +1,18 @@ +{{- if and .Values.worker.enable .Values.worker.rbac.create }} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: {{ include "node-feature-discovery.fullname" . }}-worker +subjects: +- kind: ServiceAccount + name: {{ include "node-feature-discovery.worker.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} +{{- end }} + diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/service.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/service.yaml new file mode 100644 index 000000000..7191dca70 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/service.yaml @@ -0,0 +1,20 @@ +{{- if and (not (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi)) .Values.master.enable }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-master + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: master +spec: + type: {{ .Values.master.service.type }} + ports: + - port: {{ .Values.master.service.port | default "8080" }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + {{- include "node-feature-discovery.selectorLabels" . | nindent 4 }} + role: master +{{- end}} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/serviceaccount.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/serviceaccount.yaml new file mode 100644 index 000000000..59edc5e6c --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/serviceaccount.yaml @@ -0,0 +1,58 @@ +{{- if and .Values.master.enable .Values.master.serviceAccount.create }} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.master.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.master.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.topologyUpdater.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + +{{- if and .Values.gc.enable .Values.gc.serviceAccount.create (or (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi) .Values.topologyUpdater.enable) }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.gc.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.gc.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} + +{{- if and .Values.worker.enable .Values.worker.serviceAccount.create }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "node-feature-discovery.worker.serviceAccountName" . }} + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + {{- with .Values.worker.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater-crds.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater-crds.yaml new file mode 100644 index 000000000..b6b919689 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater-crds.yaml @@ -0,0 +1,278 @@ +{{- if and .Values.topologyUpdater.enable .Values.topologyUpdater.createCRDs -}} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + api-approved.kubernetes.io: https://github.com/kubernetes/enhancements/pull/1870 + controller-gen.kubebuilder.io/version: v0.11.2 + creationTimestamp: null + name: noderesourcetopologies.topology.node.k8s.io +spec: + group: topology.node.k8s.io + names: + kind: NodeResourceTopology + listKind: NodeResourceTopologyList + plural: noderesourcetopologies + shortNames: + - node-res-topo + singular: noderesourcetopology + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: NodeResourceTopology describes node resources and their topology. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + topologyPolicies: + items: + type: string + type: array + zones: + description: ZoneList contains an array of Zone objects. + items: + description: Zone represents a resource topology zone, e.g. socket, + node, die or core. + properties: + attributes: + description: AttributeList contains an array of AttributeInfo objects. + items: + description: AttributeInfo contains one attribute of a Zone. + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + costs: + description: CostList contains an array of CostInfo objects. + items: + description: CostInfo describes the cost (or distance) between + two Zones. + properties: + name: + type: string + value: + format: int64 + type: integer + required: + - name + - value + type: object + type: array + name: + type: string + parent: + type: string + resources: + description: ResourceInfoList contains an array of ResourceInfo + objects. + items: + description: ResourceInfo contains information about one resource + type. + properties: + allocatable: + anyOf: + - type: integer + - type: string + description: Allocatable quantity of the resource, corresponding + to allocatable in node status, i.e. total amount of this + resource available to be used by pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + available: + anyOf: + - type: integer + - type: string + description: Available is the amount of this resource currently + available for new (to be scheduled) pods, i.e. Allocatable + minus the resources reserved by currently running pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + capacity: + anyOf: + - type: integer + - type: string + description: Capacity of the resource, corresponding to capacity + in node status, i.e. total amount of this resource that + the node has. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + name: + description: Name of the resource. + type: string + required: + - allocatable + - available + - capacity + - name + type: object + type: array + type: + type: string + required: + - name + - type + type: object + type: array + required: + - topologyPolicies + - zones + type: object + served: true + storage: false + - name: v1alpha2 + schema: + openAPIV3Schema: + description: NodeResourceTopology describes node resources and their topology. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + attributes: + description: AttributeList contains an array of AttributeInfo objects. + items: + description: AttributeInfo contains one attribute of a Zone. + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + topologyPolicies: + description: 'DEPRECATED (to be removed in v1beta1): use top level attributes + if needed' + items: + type: string + type: array + zones: + description: ZoneList contains an array of Zone objects. + items: + description: Zone represents a resource topology zone, e.g. socket, + node, die or core. + properties: + attributes: + description: AttributeList contains an array of AttributeInfo objects. + items: + description: AttributeInfo contains one attribute of a Zone. + properties: + name: + type: string + value: + type: string + required: + - name + - value + type: object + type: array + costs: + description: CostList contains an array of CostInfo objects. + items: + description: CostInfo describes the cost (or distance) between + two Zones. + properties: + name: + type: string + value: + format: int64 + type: integer + required: + - name + - value + type: object + type: array + name: + type: string + parent: + type: string + resources: + description: ResourceInfoList contains an array of ResourceInfo + objects. + items: + description: ResourceInfo contains information about one resource + type. + properties: + allocatable: + anyOf: + - type: integer + - type: string + description: Allocatable quantity of the resource, corresponding + to allocatable in node status, i.e. total amount of this + resource available to be used by pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + available: + anyOf: + - type: integer + - type: string + description: Available is the amount of this resource currently + available for new (to be scheduled) pods, i.e. Allocatable + minus the resources reserved by currently running pods. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + capacity: + anyOf: + - type: integer + - type: string + description: Capacity of the resource, corresponding to capacity + in node status, i.e. total amount of this resource that + the node has. + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + name: + description: Name of the resource. + type: string + required: + - allocatable + - available + - capacity + - name + type: object + type: array + type: + type: string + required: + - name + - type + type: object + type: array + required: + - zones + type: object + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater.yaml new file mode 100644 index 000000000..ba0214c88 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/topologyupdater.yaml @@ -0,0 +1,171 @@ +{{- if .Values.topologyUpdater.enable -}} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: topology-updater + {{- with .Values.topologyUpdater.daemonsetAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: {{ .Values.topologyUpdater.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: topology-updater + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: topology-updater + {{- with .Values.topologyUpdater.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + serviceAccountName: {{ include "node-feature-discovery.topologyUpdater.serviceAccountName" . }} + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.topologyUpdater.podSecurityContext | nindent 8 }} + hostNetwork: {{ .Values.topologyUpdater.hostNetwork }} + containers: + - name: topology-updater + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + livenessProbe: + {{- toYaml .Values.topologyUpdater.livenessProbe | nindent 10 }} + readinessProbe: + {{- toYaml .Values.topologyUpdater.readinessProbe | nindent 10 }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: NODE_ADDRESS + valueFrom: + fieldRef: + fieldPath: status.hostIP + {{- with .Values.topologyUpdater.extraEnvs }} + {{- toYaml . | nindent 8 }} + {{- end}} + command: + - "nfd-topology-updater" + args: + - "-podresources-socket=/host-var/lib/kubelet-podresources/kubelet.sock" + {{- if .Values.topologyUpdater.updateInterval | empty | not }} + - "-sleep-interval={{ .Values.topologyUpdater.updateInterval }}" + {{- else }} + - "-sleep-interval=3s" + {{- end }} + {{- if .Values.topologyUpdater.watchNamespace | empty | not }} + - "-watch-namespace={{ .Values.topologyUpdater.watchNamespace }}" + {{- else }} + - "-watch-namespace=*" + {{- end }} + {{- if .Values.tls.enable }} + - "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" + - "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" + - "-cert-file=/etc/kubernetes/node-feature-discovery/certs/tls.crt" + {{- end }} + {{- if not .Values.topologyUpdater.podSetFingerprint }} + - "-pods-fingerprint=false" + {{- end }} + {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} + - "-kubelet-config-uri=file:///host-var/kubelet-config" + {{- end }} + {{- if .Values.topologyUpdater.kubeletStateDir | empty }} + # Disable kubelet state tracking by giving an empty path + - "-kubelet-state-dir=" + {{- end }} + - -metrics={{ .Values.topologyUpdater.metricsPort | default "8081"}} + - "-grpc-health={{ .Values.topologyUpdater.healthPort | default "8082" }}" + ports: + - containerPort: {{ .Values.topologyUpdater.metricsPort | default "8081"}} + name: metrics + - containerPort: {{ .Values.topologyUpdater.healthPort | default "8082" }} + name: health + volumeMounts: + {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} + - name: kubelet-config + mountPath: /host-var/kubelet-config + {{- end }} + - name: kubelet-podresources-sock + mountPath: /host-var/lib/kubelet-podresources/kubelet.sock + - name: host-sys + mountPath: /host-sys + {{- if .Values.topologyUpdater.kubeletStateDir | empty | not }} + - name: kubelet-state-files + mountPath: /host-var/lib/kubelet + readOnly: true + {{- end }} + {{- if .Values.tls.enable }} + - name: nfd-topology-updater-cert + mountPath: "/etc/kubernetes/node-feature-discovery/certs" + readOnly: true + {{- end }} + - name: nfd-topology-updater-conf + mountPath: "/etc/kubernetes/node-feature-discovery" + readOnly: true + + resources: + {{- toYaml .Values.topologyUpdater.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.topologyUpdater.securityContext | nindent 12 }} + volumes: + - name: host-sys + hostPath: + path: "/sys" + {{- if .Values.topologyUpdater.kubeletConfigPath | empty | not }} + - name: kubelet-config + hostPath: + path: {{ .Values.topologyUpdater.kubeletConfigPath }} + {{- end }} + - name: kubelet-podresources-sock + hostPath: + {{- if .Values.topologyUpdater.kubeletPodResourcesSockPath | empty | not }} + path: {{ .Values.topologyUpdater.kubeletPodResourcesSockPath }} + {{- else }} + path: /var/lib/kubelet/pod-resources/kubelet.sock + {{- end }} + {{- if .Values.topologyUpdater.kubeletStateDir | empty | not }} + - name: kubelet-state-files + hostPath: + path: {{ .Values.topologyUpdater.kubeletStateDir }} + {{- end }} + - name: nfd-topology-updater-conf + configMap: + name: {{ include "node-feature-discovery.fullname" . }}-topology-updater-conf + items: + - key: nfd-topology-updater.conf + path: nfd-topology-updater.conf + {{- if .Values.tls.enable }} + - name: nfd-topology-updater-cert + secret: + secretName: nfd-topology-updater-cert + {{- end }} + + + {{- with .Values.topologyUpdater.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologyUpdater.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologyUpdater.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/worker.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/worker.yaml new file mode 100644 index 000000000..755466c75 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/templates/worker.yaml @@ -0,0 +1,186 @@ +{{- if .Values.worker.enable }} +apiVersion: apps/v1 +kind: DaemonSet +metadata: + name: {{ include "node-feature-discovery.fullname" . }}-worker + namespace: {{ include "node-feature-discovery.namespace" . }} + labels: + {{- include "node-feature-discovery.labels" . | nindent 4 }} + role: worker + {{- with .Values.worker.daemonsetAnnotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + revisionHistoryLimit: {{ .Values.worker.revisionHistoryLimit }} + selector: + matchLabels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 6 }} + role: worker + template: + metadata: + labels: + {{- include "node-feature-discovery.selectorLabels" . | nindent 8 }} + role: worker + {{- with .Values.worker.annotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + dnsPolicy: ClusterFirstWithHostNet + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "node-feature-discovery.worker.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.worker.podSecurityContext | nindent 8 }} + hostNetwork: {{ .Values.worker.hostNetwork }} + containers: + - name: worker + securityContext: + {{- toYaml .Values.worker.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + livenessProbe: + {{- toYaml .Values.worker.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.worker.readinessProbe | nindent 12 }} + env: + - name: NODE_NAME + valueFrom: + fieldRef: + fieldPath: spec.nodeName + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: POD_UID + valueFrom: + fieldRef: + fieldPath: metadata.uid + {{- with .Values.worker.extraEnvs }} + {{- toYaml . | nindent 8 }} + {{- end}} + resources: + {{- toYaml .Values.worker.resources | nindent 12 }} + command: + - "nfd-worker" + args: +{{- if not (and .Values.featureGates.NodeFeatureAPI .Values.enableNodeFeatureApi) }} + - "-server={{ include "node-feature-discovery.fullname" . }}-master:{{ .Values.master.service.port }}" +{{- end }} +{{- if .Values.tls.enable }} + - "-ca-file=/etc/kubernetes/node-feature-discovery/certs/ca.crt" + - "-key-file=/etc/kubernetes/node-feature-discovery/certs/tls.key" + - "-cert-file=/etc/kubernetes/node-feature-discovery/certs/tls.crt" +{{- end }} +# Go over featureGate and add the feature-gate flag +{{- range $key, $value := .Values.featureGates }} + - "-feature-gates={{ $key }}={{ $value }}" +{{- end }} + - "-metrics={{ .Values.worker.metricsPort | default "8081"}}" + - "-grpc-health={{ .Values.worker.healthPort | default "8082" }}" + ports: + - containerPort: {{ .Values.worker.metricsPort | default "8081"}} + name: metrics + - containerPort: {{ .Values.worker.healthPort | default "8082" }} + name: health + volumeMounts: + - name: host-boot + mountPath: "/host-boot" + readOnly: true + - name: host-os-release + mountPath: "/host-etc/os-release" + readOnly: true + - name: host-sys + mountPath: "/host-sys" + readOnly: true + - name: host-usr-lib + mountPath: "/host-usr/lib" + readOnly: true + - name: host-lib + mountPath: "/host-lib" + readOnly: true + - name: host-proc-swaps + mountPath: "/host-proc/swaps" + readOnly: true + {{- if .Values.worker.mountUsrSrc }} + - name: host-usr-src + mountPath: "/host-usr/src" + readOnly: true + {{- end }} + - name: source-d + mountPath: "/etc/kubernetes/node-feature-discovery/source.d/" + readOnly: true + - name: features-d + mountPath: "/etc/kubernetes/node-feature-discovery/features.d/" + readOnly: true + - name: nfd-worker-conf + mountPath: "/etc/kubernetes/node-feature-discovery" + readOnly: true +{{- if .Values.tls.enable }} + - name: nfd-worker-cert + mountPath: "/etc/kubernetes/node-feature-discovery/certs" + readOnly: true +{{- end }} + volumes: + - name: host-boot + hostPath: + path: "/boot" + - name: host-os-release + hostPath: + path: "/etc/os-release" + - name: host-sys + hostPath: + path: "/sys" + - name: host-usr-lib + hostPath: + path: "/usr/lib" + - name: host-lib + hostPath: + path: "/lib" + - name: host-proc-swaps + hostPath: + path: "/proc/swaps" + {{- if .Values.worker.mountUsrSrc }} + - name: host-usr-src + hostPath: + path: "/usr/src" + {{- end }} + - name: source-d + hostPath: + path: "/etc/kubernetes/node-feature-discovery/source.d/" + - name: features-d + hostPath: + path: "/etc/kubernetes/node-feature-discovery/features.d/" + - name: nfd-worker-conf + configMap: + name: {{ include "node-feature-discovery.fullname" . }}-worker-conf + items: + - key: nfd-worker.conf + path: nfd-worker.conf +{{- if .Values.tls.enable }} + - name: nfd-worker-cert + secret: + secretName: nfd-worker-cert +{{- end }} + {{- with .Values.worker.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.worker.priorityClassName }} + priorityClassName: {{ . | quote }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/values.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/values.yaml new file mode 100644 index 000000000..2d24983db --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/charts/node-feature-discovery/values.yaml @@ -0,0 +1,593 @@ +image: + repository: registry.k8s.io/nfd/node-feature-discovery + # This should be set to 'IfNotPresent' for released version + pullPolicy: IfNotPresent + # tag, if defined will use the given image tag, else Chart.AppVersion will be used + # tag +imagePullSecrets: [] + +nameOverride: "" +fullnameOverride: "" +namespaceOverride: "" + +enableNodeFeatureApi: true + +featureGates: + NodeFeatureAPI: true + NodeFeatureGroupAPI: false + +priorityClassName: "" + +master: + enable: true + extraEnvs: [] + hostNetwork: false + config: ### + # noPublish: false + # autoDefaultNs: true + # extraLabelNs: ["added.ns.io","added.kubernets.io"] + # denyLabelNs: ["denied.ns.io","denied.kubernetes.io"] + # resourceLabels: ["vendor-1.com/feature-1","vendor-2.io/feature-2"] + # enableTaints: false + # labelWhiteList: "foo" + # resyncPeriod: "2h" + # klog: + # addDirHeader: false + # alsologtostderr: false + # logBacktraceAt: + # logtostderr: true + # skipHeaders: false + # stderrthreshold: 2 + # v: 0 + # vmodule: + ## NOTE: the following options are not dynamically run-time configurable + ## and require a nfd-master restart to take effect after being changed + # logDir: + # logFile: + # logFileMaxSize: 1800 + # skipLogHeaders: false + # leaderElection: + # leaseDuration: 15s + # # this value has to be lower than leaseDuration and greater than retryPeriod*1.2 + # renewDeadline: 10s + # # this value has to be greater than 0 + # retryPeriod: 2s + # nfdApiParallelism: 10 + ### + # The TCP port that nfd-master listens for incoming requests. Default: 8080 + # Deprecated this parameter is related to the deprecated gRPC API and will + # be removed with it in a future release + port: 8080 + metricsPort: 8081 + healthPort: 8082 + instance: + featureApi: + resyncPeriod: + denyLabelNs: [] + extraLabelNs: [] + resourceLabels: [] + enableTaints: false + crdController: null + featureRulesController: null + nfdApiParallelism: null + deploymentAnnotations: {} + replicaCount: 1 + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsNonRoot: true + # runAsUser: 1000 + + serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + + # specify how many old ReplicaSets for the Deployment to retain. + revisionHistoryLimit: + + rbac: + create: true + + service: + type: ClusterIP + port: 8080 + + resources: + limits: + memory: 4Gi + requests: + cpu: 100m + # You may want to use the same value for `requests.memory` and `limits.memory`. The “requests” value affects scheduling to accommodate pods on nodes. + # If there is a large difference between “requests” and “limits” and nodes experience memory pressure, the kernel may invoke + # the OOM Killer, even if the memory does not exceed the “limits” threshold. This can cause unexpected pod evictions. Memory + # cannot be compressed and once allocated to a pod, it can only be reclaimed by killing the pod. + # Natan Yellin 22/09/2022 https://home.robusta.dev/blog/kubernetes-memory-limit + memory: 128Mi + + nodeSelector: {} + + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Equal" + value: "" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Equal" + value: "" + effect: "NoSchedule" + + annotations: {} + + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: "node-role.kubernetes.io/master" + operator: In + values: [""] + - weight: 1 + preference: + matchExpressions: + - key: "node-role.kubernetes.io/control-plane" + operator: In + values: [""] + + livenessProbe: + grpc: + port: 8082 + initialDelaySeconds: 10 + # failureThreshold: 3 + # periodSeconds: 10 + readinessProbe: + grpc: + port: 8082 + initialDelaySeconds: 5 + failureThreshold: 10 + # periodSeconds: 10 + +worker: + enable: true + extraEnvs: [] + hostNetwork: false + config: ### + #core: + # labelWhiteList: + # noPublish: false + # sleepInterval: 60s + # featureSources: [all] + # labelSources: [all] + # klog: + # addDirHeader: false + # alsologtostderr: false + # logBacktraceAt: + # logtostderr: true + # skipHeaders: false + # stderrthreshold: 2 + # v: 0 + # vmodule: + ## NOTE: the following options are not dynamically run-time configurable + ## and require a nfd-worker restart to take effect after being changed + # logDir: + # logFile: + # logFileMaxSize: 1800 + # skipLogHeaders: false + #sources: + # cpu: + # cpuid: + ## NOTE: whitelist has priority over blacklist + # attributeBlacklist: + # - "AVX10" + # - "BMI1" + # - "BMI2" + # - "CLMUL" + # - "CMOV" + # - "CX16" + # - "ERMS" + # - "F16C" + # - "HTT" + # - "LZCNT" + # - "MMX" + # - "MMXEXT" + # - "NX" + # - "POPCNT" + # - "RDRAND" + # - "RDSEED" + # - "RDTSCP" + # - "SGX" + # - "SSE" + # - "SSE2" + # - "SSE3" + # - "SSE4" + # - "SSE42" + # - "SSSE3" + # - "TDX_GUEST" + # attributeWhitelist: + # kernel: + # kconfigFile: "/path/to/kconfig" + # configOpts: + # - "NO_HZ" + # - "X86" + # - "DMI" + # pci: + # deviceClassWhitelist: + # - "0200" + # - "03" + # - "12" + # deviceLabelFields: + # - "class" + # - "vendor" + # - "device" + # - "subsystem_vendor" + # - "subsystem_device" + # usb: + # deviceClassWhitelist: + # - "0e" + # - "ef" + # - "fe" + # - "ff" + # deviceLabelFields: + # - "class" + # - "vendor" + # - "device" + # local: + # hooksEnabled: false + # custom: + # # The following feature demonstrates the capabilities of the matchFeatures + # - name: "my custom rule" + # labels: + # "vendor.io/my-ng-feature": "true" + # # matchFeatures implements a logical AND over all matcher terms in the + # # list (i.e. all of the terms, or per-feature matchers, must match) + # matchFeatures: + # - feature: cpu.cpuid + # matchExpressions: + # AVX512F: {op: Exists} + # - feature: cpu.cstate + # matchExpressions: + # enabled: {op: IsTrue} + # - feature: cpu.pstate + # matchExpressions: + # no_turbo: {op: IsFalse} + # scaling_governor: {op: In, value: ["performance"]} + # - feature: cpu.rdt + # matchExpressions: + # RDTL3CA: {op: Exists} + # - feature: cpu.sst + # matchExpressions: + # bf.enabled: {op: IsTrue} + # - feature: cpu.topology + # matchExpressions: + # hardware_multithreading: {op: IsFalse} + # + # - feature: kernel.config + # matchExpressions: + # X86: {op: Exists} + # LSM: {op: InRegexp, value: ["apparmor"]} + # - feature: kernel.loadedmodule + # matchExpressions: + # e1000e: {op: Exists} + # - feature: kernel.selinux + # matchExpressions: + # enabled: {op: IsFalse} + # - feature: kernel.version + # matchExpressions: + # major: {op: In, value: ["5"]} + # minor: {op: Gt, value: ["10"]} + # + # - feature: storage.block + # matchExpressions: + # rotational: {op: In, value: ["0"]} + # dax: {op: In, value: ["0"]} + # + # - feature: network.device + # matchExpressions: + # operstate: {op: In, value: ["up"]} + # speed: {op: Gt, value: ["100"]} + # + # - feature: memory.numa + # matchExpressions: + # node_count: {op: Gt, value: ["2"]} + # - feature: memory.nv + # matchExpressions: + # devtype: {op: In, value: ["nd_dax"]} + # mode: {op: In, value: ["memory"]} + # + # - feature: system.osrelease + # matchExpressions: + # ID: {op: In, value: ["fedora", "centos"]} + # - feature: system.name + # matchExpressions: + # nodename: {op: InRegexp, value: ["^worker-X"]} + # + # - feature: local.label + # matchExpressions: + # custom-feature-knob: {op: Gt, value: ["100"]} + # + # # The following feature demonstrates the capabilities of the matchAny + # - name: "my matchAny rule" + # labels: + # "vendor.io/my-ng-feature-2": "my-value" + # # matchAny implements a logical IF over all elements (sub-matchers) in + # # the list (i.e. at least one feature matcher must match) + # matchAny: + # - matchFeatures: + # - feature: kernel.loadedmodule + # matchExpressions: + # driver-module-X: {op: Exists} + # - feature: pci.device + # matchExpressions: + # vendor: {op: In, value: ["8086"]} + # class: {op: In, value: ["0200"]} + # - matchFeatures: + # - feature: kernel.loadedmodule + # matchExpressions: + # driver-module-Y: {op: Exists} + # - feature: usb.device + # matchExpressions: + # vendor: {op: In, value: ["8086"]} + # class: {op: In, value: ["02"]} + # + # - name: "avx wildcard rule" + # labels: + # "my-avx-feature": "true" + # matchFeatures: + # - feature: cpu.cpuid + # matchName: {op: InRegexp, value: ["^AVX512"]} + # + # # The following features demonstreate label templating capabilities + # - name: "my template rule" + # labelsTemplate: | + # {{ range .system.osrelease }}vendor.io/my-system-feature.{{ .Name }}={{ .Value }} + # {{ end }} + # matchFeatures: + # - feature: system.osrelease + # matchExpressions: + # ID: {op: InRegexp, value: ["^open.*"]} + # VERSION_ID.major: {op: In, value: ["13", "15"]} + # + # - name: "my template rule 2" + # labelsTemplate: | + # {{ range .pci.device }}vendor.io/my-pci-device.{{ .class }}-{{ .device }}=with-cpuid + # {{ end }} + # matchFeatures: + # - feature: pci.device + # matchExpressions: + # class: {op: InRegexp, value: ["^06"]} + # vendor: ["8086"] + # - feature: cpu.cpuid + # matchExpressions: + # AVX: {op: Exists} + # + # # The following examples demonstrate vars field and back-referencing + # # previous labels and vars + # - name: "my dummy kernel rule" + # labels: + # "vendor.io/my.kernel.feature": "true" + # matchFeatures: + # - feature: kernel.version + # matchExpressions: + # major: {op: Gt, value: ["2"]} + # + # - name: "my dummy rule with no labels" + # vars: + # "my.dummy.var": "1" + # matchFeatures: + # - feature: cpu.cpuid + # matchExpressions: {} + # + # - name: "my rule using backrefs" + # labels: + # "vendor.io/my.backref.feature": "true" + # matchFeatures: + # - feature: rule.matched + # matchExpressions: + # vendor.io/my.kernel.feature: {op: IsTrue} + # my.dummy.var: {op: Gt, value: ["0"]} + # + # - name: "kconfig template rule" + # labelsTemplate: | + # {{ range .kernel.config }}kconfig-{{ .Name }}={{ .Value }} + # {{ end }} + # matchFeatures: + # - feature: kernel.config + # matchName: {op: In, value: ["SWAP", "X86", "ARM"]} +### + + metricsPort: 8081 + healthPort: 8082 + daemonsetAnnotations: {} + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsNonRoot: true + # runAsUser: 1000 + + livenessProbe: + grpc: + port: 8082 + initialDelaySeconds: 10 + # failureThreshold: 3 + # periodSeconds: 10 + readinessProbe: + grpc: + port: 8082 + initialDelaySeconds: 5 + failureThreshold: 10 + # periodSeconds: 10 + + serviceAccount: + # Specifies whether a service account should be created. + # We create this by default to make it easier for downstream users to apply PodSecurityPolicies. + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + + # specify how many old ControllerRevisions for the DaemonSet to retain. + revisionHistoryLimit: + + rbac: + create: true + + # Allow users to mount the hostPath /usr/src, useful for RHCOS on s390x + # Does not work on systems without /usr/src AND a read-only /usr, such as Talos + mountUsrSrc: false + + resources: + limits: + memory: 512Mi + requests: + cpu: 5m + memory: 64Mi + + nodeSelector: {} + + tolerations: [] + + annotations: {} + + affinity: {} + + priorityClassName: "" + +topologyUpdater: + config: ### + ## key = node name, value = list of resources to be excluded. + ## use * to exclude from all nodes. + ## an example for how the exclude list should looks like + #excludeList: + # node1: [cpu] + # node2: [memory, example/deviceA] + # *: [hugepages-2Mi] +### + + enable: false + createCRDs: false + extraEnvs: [] + hostNetwork: false + + serviceAccount: + create: true + annotations: {} + name: + + # specify how many old ControllerRevisions for the DaemonSet to retain. + revisionHistoryLimit: + + rbac: + create: true + + metricsPort: 8081 + healthPort: 8082 + kubeletConfigPath: + kubeletPodResourcesSockPath: + updateInterval: 60s + watchNamespace: "*" + kubeletStateDir: /var/lib/kubelet + + podSecurityContext: {} + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: [ "ALL" ] + readOnlyRootFilesystem: true + runAsUser: 0 + + livenessProbe: + grpc: + port: 8082 + initialDelaySeconds: 10 + # failureThreshold: 3 + # periodSeconds: 10 + readinessProbe: + grpc: + port: 8082 + initialDelaySeconds: 5 + failureThreshold: 10 + # periodSeconds: 10 + + resources: + limits: + memory: 60Mi + requests: + cpu: 50m + memory: 40Mi + + nodeSelector: {} + tolerations: [] + annotations: {} + daemonsetAnnotations: {} + affinity: {} + podSetFingerprint: true + +gc: + enable: true + extraEnvs: [] + hostNetwork: false + replicaCount: 1 + + serviceAccount: + create: true + annotations: {} + name: + rbac: + create: true + + interval: 1h + + podSecurityContext: {} + + resources: + limits: + memory: 1Gi + requests: + cpu: 10m + memory: 128Mi + + metricsPort: 8081 + + nodeSelector: {} + tolerations: [] + annotations: {} + deploymentAnnotations: {} + affinity: {} + + # specify how many old ReplicaSets for the Deployment to retain. + revisionHistoryLimit: + +# Optionally use encryption for worker <--> master comms +# TODO: verify hostname is not yet supported +# +# If you do not enable certManager (and have it installed) you will +# need to manually, or otherwise, provision the TLS certs as secrets +tls: + enable: false + certManager: false + certManagerCertificate: + issuerKind: + issuerName: + +prometheus: + enable: false + scrapeInterval: 10s + labels: {} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_clusterpolicies.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_clusterpolicies.yaml new file mode 100644 index 000000000..8ee8e9a8a --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_clusterpolicies.yaml @@ -0,0 +1,2384 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: clusterpolicies.nvidia.com +spec: + group: nvidia.com + names: + kind: ClusterPolicy + listKind: ClusterPolicyList + plural: clusterpolicies + singular: clusterpolicy + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: string + name: v1 + schema: + openAPIV3Schema: + description: ClusterPolicy is the Schema for the clusterpolicies API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: ClusterPolicySpec defines the desired state of ClusterPolicy + properties: + ccManager: + description: CCManager component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + defaultMode: + description: Default CC mode setting for compatible GPUs on the + node + enum: + - "on" + - "off" + - devtools + type: string + enabled: + description: Enabled indicates if deployment of CC Manager is + enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: CC Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: CC Manager image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: CC Manager image tag + type: string + type: object + cdi: + description: CDI configures how the Container Device Interface is + used in the cluster + properties: + default: + default: false + description: Default indicates whether to use CDI as the default + mechanism for providing GPU access to containers. + type: boolean + enabled: + default: false + description: Enabled indicates whether CDI can be used to make + GPUs accessible to containers. + type: boolean + type: object + daemonsets: + description: Daemonset defines common configuration for all Daemonsets + properties: + annotations: + additionalProperties: + type: string + description: |- + Optional: Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + type: object + labels: + additionalProperties: + type: string + description: |- + Optional: Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + type: object + priorityClassName: + type: string + rollingUpdate: + description: 'Optional: Configuration for rolling update of all + DaemonSet pods' + properties: + maxUnavailable: + type: string + type: object + tolerations: + description: 'Optional: Set tolerations' + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + updateStrategy: + default: RollingUpdate + enum: + - RollingUpdate + - OnDelete + type: string + type: object + dcgm: + description: DCGM component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if deployment of NVIDIA DCGM Hostengine + as a separate pod is enabled. + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + hostPort: + description: 'Deprecated: HostPort represents host port that needs + to be bound for DCGM engine (Default: 5555)' + format: int32 + type: integer + image: + description: NVIDIA DCGM image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA DCGM image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA DCGM image tag + type: string + type: object + dcgmExporter: + description: DCGMExporter spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + config: + description: 'Optional: Custom metrics configuration for NVIDIA + DCGM Exporter' + properties: + name: + description: ConfigMap name with file dcgm-metrics.csv for + metrics to be collected by NVIDIA DCGM Exporter + type: string + type: object + enabled: + description: Enabled indicates if deployment of NVIDIA DCGM Exporter + through operator is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA DCGM Exporter image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA DCGM Exporter image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + serviceMonitor: + description: 'Optional: ServiceMonitor configuration for NVIDIA + DCGM Exporter' + properties: + additionalLabels: + additionalProperties: + type: string + description: AdditionalLabels to add to ServiceMonitor instance + for NVIDIA DCGM Exporter + type: object + enabled: + description: Enabled indicates if ServiceMonitor is deployed + for NVIDIA DCGM Exporter + type: boolean + honorLabels: + description: HonorLabels chooses the metric’s labels on collisions + with target labels. + type: boolean + interval: + description: |- + Interval which metrics should be scraped from NVIDIA DCGM Exporter. If not specified Prometheus’ global scrape interval is used. + Supported units: y, w, d, h, m, s, ms + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + relabelings: + description: Relabelings allows to rewrite labels on metric + sets for NVIDIA DCGM Exporter + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + Action to perform based on the regex matching. + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + Modulus to take of the hash of the source label values. + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: Regular expression against which the extracted + value is matched. + type: string + replacement: + description: |- + Replacement value against which a Replace action is performed if the + regular expression matches. + + Regex capture groups are available. + type: string + separator: + description: Separator is the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + The source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: |- + Label to which the resulting string is written in a replacement. + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + Regex capture groups are available. + type: string + type: object + type: array + type: object + version: + description: NVIDIA DCGM Exporter image tag + type: string + type: object + devicePlugin: + description: DevicePlugin component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + config: + description: 'Optional: Configuration for the NVIDIA Device Plugin + via the ConfigMap' + properties: + default: + description: Default config name within the ConfigMap for + the NVIDIA Device Plugin config + type: string + name: + description: ConfigMap name for NVIDIA Device Plugin config + including shared config between plugin and GFD + type: string + type: object + enabled: + description: Enabled indicates if deployment of NVIDIA Device + Plugin through operator is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA Device Plugin image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + mps: + description: 'Optional: MPS related configuration for the NVIDIA + Device Plugin' + properties: + root: + default: /run/nvidia/mps + description: Root defines the MPS root path on the host + type: string + type: object + repository: + description: NVIDIA Device Plugin image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA Device Plugin image tag + type: string + type: object + driver: + description: Driver component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + certConfig: + description: 'Optional: Custom certificates configuration for + NVIDIA Driver container' + properties: + name: + type: string + type: object + enabled: + description: Enabled indicates if deployment of NVIDIA Driver + through operator is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA Driver image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + kernelModuleConfig: + description: 'Optional: Kernel module configuration parameters + for the NVIDIA Driver' + properties: + name: + type: string + type: object + licensingConfig: + description: 'Optional: Licensing configuration for NVIDIA vGPU + licensing' + properties: + configMapName: + type: string + nlsEnabled: + description: NLSEnabled indicates if NVIDIA Licensing System + is used for licensing. + type: boolean + type: object + livenessProbe: + description: NVIDIA Driver container liveness probe settings + properties: + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + minimum: 1 + type: integer + type: object + manager: + description: Manager represents configuration for NVIDIA Driver + Manager initContainer + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Image represents NVIDIA Driver Manager image + name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Repository represents Driver Managerrepository + path + type: string + version: + description: Version represents NVIDIA Driver Manager image + tag(version) + type: string + type: object + rdma: + description: GPUDirectRDMASpec defines the properties for nvidia-peermem + deployment + properties: + enabled: + description: Enabled indicates if GPUDirect RDMA is enabled + through GPU operator + type: boolean + useHostMofed: + description: UseHostMOFED indicates to use MOFED drivers directly + installed on the host to enable GPUDirect RDMA + type: boolean + type: object + readinessProbe: + description: NVIDIA Driver container readiness probe settings + properties: + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + minimum: 1 + type: integer + type: object + repoConfig: + description: 'Optional: Custom repo configuration for NVIDIA Driver + container' + properties: + configMapName: + type: string + type: object + repository: + description: NVIDIA Driver image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + startupProbe: + description: NVIDIA Driver container startup probe settings + properties: + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + minimum: 1 + type: integer + type: object + upgradePolicy: + description: Driver auto-upgrade settings + properties: + autoUpgrade: + default: false + description: |- + AutoUpgrade is a global switch for automatic upgrade feature + if set to false all other options are ignored + type: boolean + drain: + description: DrainSpec describes configuration for node drain + during automatic upgrade + properties: + deleteEmptyDir: + default: false + description: |- + DeleteEmptyDir indicates if should continue even if there are pods using emptyDir + (local data that will be deleted when the node is drained) + type: boolean + enable: + default: false + description: Enable indicates if node draining is allowed + during upgrade + type: boolean + force: + default: false + description: Force indicates if force draining is allowed + type: boolean + podSelector: + description: |- + PodSelector specifies a label selector to filter pods on the node that need to be drained + For more details on label selectors, see: + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + type: string + timeoutSeconds: + default: 300 + description: TimeoutSecond specifies the length of time + in seconds to wait before giving up drain, zero means + infinite + minimum: 0 + type: integer + type: object + maxParallelUpgrades: + default: 1 + description: |- + MaxParallelUpgrades indicates how many nodes can be upgraded in parallel + 0 means no limit, all nodes will be upgraded in parallel + minimum: 0 + type: integer + maxUnavailable: + anyOf: + - type: integer + - type: string + default: 25% + description: |- + MaxUnavailable is the maximum number of nodes with the driver installed, that can be unavailable during the upgrade. + Value can be an absolute number (ex: 5) or a percentage of total nodes at the start of upgrade (ex: 10%). + Absolute number is calculated from percentage by rounding up. + By default, a fixed value of 25% is used. + x-kubernetes-int-or-string: true + podDeletion: + description: PodDeletionSpec describes configuration for deletion + of pods using special resources during automatic upgrade + properties: + deleteEmptyDir: + default: false + description: |- + DeleteEmptyDir indicates if should continue even if there are pods using emptyDir + (local data that will be deleted when the pod is deleted) + type: boolean + force: + default: false + description: Force indicates if force deletion is allowed + type: boolean + timeoutSeconds: + default: 300 + description: |- + TimeoutSecond specifies the length of time in seconds to wait before giving up on pod termination, zero means + infinite + minimum: 0 + type: integer + type: object + waitForCompletion: + description: WaitForCompletionSpec describes the configuration + for waiting on job completions + properties: + podSelector: + description: |- + PodSelector specifies a label selector for the pods to wait for completion + For more details on label selectors, see: + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors + type: string + timeoutSeconds: + default: 0 + description: |- + TimeoutSecond specifies the length of time in seconds to wait before giving up on pod termination, zero means + infinite + minimum: 0 + type: integer + type: object + type: object + useNvidiaDriverCRD: + description: UseNvidiaDriverCRD indicates if the deployment of + NVIDIA Driver is managed by the NVIDIADriver CRD type + type: boolean + useOpenKernelModules: + description: UseOpenKernelModules indicates if the open GPU kernel + modules should be used + type: boolean + usePrecompiled: + description: UsePrecompiled indicates if deployment of NVIDIA + Driver using pre-compiled modules is enabled + type: boolean + version: + description: NVIDIA Driver image tag + type: string + virtualTopology: + description: 'Optional: Virtual Topology Daemon configuration + for NVIDIA vGPU drivers' + properties: + config: + description: 'Optional: Config name representing virtual topology + daemon configuration file nvidia-topologyd.conf' + type: string + type: object + type: object + gdrcopy: + description: GDRCopy component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if GDRCopy is enabled through GPU + Operator + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA GDRCopy driver image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA GDRCopy driver image repository + type: string + version: + description: NVIDIA GDRCopy driver image tag + type: string + type: object + gds: + description: GPUDirectStorage defines the spec for GDS components(Experimental) + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if GPUDirect Storage is enabled + through GPU operator + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA GPUDirect Storage Driver image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA GPUDirect Storage Driver image repository + type: string + version: + description: NVIDIA GPUDirect Storage Driver image tag + type: string + type: object + gfd: + description: GPUFeatureDiscovery spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if deployment of GPU Feature Discovery + Plugin is enabled. + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: GFD image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: GFD image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: GFD image tag + type: string + type: object + hostPaths: + description: HostPaths defines various paths on the host needed by + GPU Operator components + properties: + driverInstallDir: + description: |- + DriverInstallDir represents the root at which driver files including libraries, + config files, and executables can be found. + type: string + rootFS: + description: |- + RootFS represents the path to the root filesystem of the host. + This is used by components that need to interact with the host filesystem + and as such this must be a chroot-able filesystem. + Examples include the MIG Manager and Toolkit Container which may need to + stop, start, or restart systemd services. + type: string + type: object + kataManager: + description: KataManager component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + config: + description: Kata Manager config + properties: + artifactsDir: + default: /opt/nvidia-gpu-operator/artifacts/runtimeclasses + description: |- + ArtifactsDir is the directory where kata artifacts (e.g. kernel / guest images, configuration, etc.) + are placed on the local filesystem. + type: string + runtimeClasses: + description: RuntimeClasses is a list of kata runtime classes + to configure. + items: + description: RuntimeClass defines the configuration for + a kata RuntimeClass + properties: + artifacts: + description: Artifacts are the kata artifacts associated + with the runtime class. + properties: + pullSecret: + description: PullSecret is the secret used to pull + the OCI artifact. + type: string + url: + description: |- + URL is the path to the OCI artifact (payload) containing all artifacts + associated with a kata runtime class. + type: string + required: + - url + type: object + name: + description: Name is the name of the kata runtime class. + type: string + nodeSelector: + additionalProperties: + type: string + description: |- + NodeSelector specifies the nodeSelector for the RuntimeClass object. + This ensures pods running with the RuntimeClass only get scheduled + onto nodes which support it. + type: object + required: + - artifacts + - name + type: object + type: array + type: object + enabled: + description: Enabled indicates if deployment of Kata Manager is + enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Kata Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Kata Manager image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: Kata Manager image tag + type: string + type: object + mig: + description: MIG spec + properties: + strategy: + description: 'Optional: MIGStrategy to apply for GFD and NVIDIA + Device Plugin' + enum: + - none + - single + - mixed + type: string + type: object + migManager: + description: MIGManager for configuration to deploy MIG Manager + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + config: + description: 'Optional: Custom mig-parted configuration for NVIDIA + MIG Manager container' + properties: + default: + default: all-disabled + description: Default MIG config to be applied on the node, + when there is no config specified with the node label nvidia.com/mig.config + enum: + - all-disabled + - "" + type: string + name: + default: default-mig-parted-config + description: ConfigMap name + type: string + type: object + enabled: + description: Enabled indicates if deployment of NVIDIA MIG Manager + is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + gpuClientsConfig: + description: 'Optional: Custom gpu-clients configuration for NVIDIA + MIG Manager container' + properties: + name: + description: ConfigMap name + type: string + type: object + image: + description: NVIDIA MIG Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA MIG Manager image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA MIG Manager image tag + type: string + type: object + nodeStatusExporter: + description: NodeStatusExporter spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if deployment of Node Status Exporter + is enabled. + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Node Status Exporter image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Node Status Exporterimage repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: Node Status Exporterimage tag + type: string + type: object + operator: + description: Operator component spec + properties: + annotations: + additionalProperties: + type: string + description: |- + Optional: Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + type: object + defaultRuntime: + default: docker + description: Runtime defines container runtime type + enum: + - docker + - crio + - containerd + type: string + initContainer: + description: InitContainerSpec describes configuration for initContainer + image used with all components + properties: + image: + description: Image represents image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Repository represents image repository path + type: string + version: + description: Version represents image tag(version) + type: string + type: object + labels: + additionalProperties: + type: string + description: |- + Optional: Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + type: object + runtimeClass: + default: nvidia + type: string + use_ocp_driver_toolkit: + description: UseOpenShiftDriverToolkit indicates if DriverToolkit + image should be used on OpenShift to build and install driver + modules + type: boolean + required: + - defaultRuntime + type: object + psa: + description: PSA defines spec for PodSecurityAdmission configuration + properties: + enabled: + description: Enabled indicates if PodSecurityAdmission configuration + needs to be enabled for all Pods + type: boolean + type: object + psp: + description: |- + Deprecated: Pod Security Policies are no longer supported. Please use PodSecurityAdmission instead + PSP defines spec for handling PodSecurityPolicies + properties: + enabled: + description: Enabled indicates if PodSecurityPolicies needs to + be enabled for all Pods + type: boolean + type: object + sandboxDevicePlugin: + description: SandboxDevicePlugin component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if deployment of NVIDIA Sandbox + Device Plugin through operator is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA Sandbox Device Plugin image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA Sandbox Device Plugin image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA Sandbox Device Plugin image tag + type: string + type: object + sandboxWorkloads: + description: SandboxWorkloads defines the spec for handling sandbox + workloads (i.e. Virtual Machines) + properties: + defaultWorkload: + default: container + description: |- + DefaultWorkload indicates the default GPU workload type to configure + worker nodes in the cluster for + enum: + - container + - vm-passthrough + - vm-vgpu + type: string + enabled: + description: |- + Enabled indicates if the GPU Operator should manage additional operands required + for sandbox workloads (i.e. VFIO Manager, vGPU Manager, and additional device plugins) + type: boolean + type: object + toolkit: + description: Toolkit component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if deployment of NVIDIA Container + Toolkit through operator is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA Container Toolkit image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + installDir: + default: /usr/local/nvidia + description: Toolkit install directory on the host + type: string + repository: + description: NVIDIA Container Toolkit image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA Container Toolkit image tag + type: string + type: object + validator: + description: Validator defines the spec for operator-validator daemonset + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + cuda: + description: CUDA validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + driver: + description: Toolkit validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Validator image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + plugin: + description: Plugin validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + repository: + description: Validator image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + toolkit: + description: Toolkit validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + version: + description: Validator image tag + type: string + vfioPCI: + description: VfioPCI validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + vgpuDevices: + description: VGPUDevices validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + vgpuManager: + description: VGPUManager validator spec + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + type: object + type: object + vfioManager: + description: VFIOManager for configuration to deploy VFIO-PCI Manager + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + driverManager: + description: DriverManager represents configuration for NVIDIA + Driver Manager + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Image represents NVIDIA Driver Manager image + name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Repository represents Driver Managerrepository + path + type: string + version: + description: Version represents NVIDIA Driver Manager image + tag(version) + type: string + type: object + enabled: + description: Enabled indicates if deployment of VFIO Manager is + enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: VFIO Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: VFIO Manager image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: VFIO Manager image tag + type: string + type: object + vgpuDeviceManager: + description: VGPUDeviceManager spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + config: + description: NVIDIA vGPU devices configuration for NVIDIA vGPU + Device Manager container + properties: + default: + default: default + description: Default config name within the ConfigMap + type: string + name: + description: ConfigMap name + type: string + type: object + enabled: + description: Enabled indicates if deployment of NVIDIA vGPU Device + Manager is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA vGPU Device Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA vGPU Device Manager image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA vGPU Device Manager image tag + type: string + type: object + vgpuManager: + description: VGPUManager component spec + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + driverManager: + description: DriverManager represents configuration for NVIDIA + Driver Manager initContainer + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Image represents NVIDIA Driver Manager image + name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Repository represents Driver Managerrepository + path + type: string + version: + description: Version represents NVIDIA Driver Manager image + tag(version) + type: string + type: object + enabled: + description: Enabled indicates if deployment of NVIDIA vGPU Manager + through operator is enabled + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA vGPU Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA vGPU Manager image repository + type: string + resources: + description: 'Optional: Define resources requests and limits for + each pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + version: + description: NVIDIA vGPU Manager image tag + type: string + type: object + required: + - daemonsets + - dcgm + - dcgmExporter + - devicePlugin + - driver + - gfd + - nodeStatusExporter + - operator + - toolkit + type: object + status: + description: ClusterPolicyStatus defines the observed state of ClusterPolicy + properties: + conditions: + description: Conditions is a list of conditions representing the ClusterPolicy's + current state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + namespace: + description: Namespace indicates a namespace in which the operator + is installed + type: string + state: + description: State indicates status of ClusterPolicy + enum: + - ignored + - ready + - notReady + type: string + required: + - state + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_nvidiadrivers.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_nvidiadrivers.yaml new file mode 100644 index 000000000..072155768 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/crds/nvidia.com_nvidiadrivers.yaml @@ -0,0 +1,797 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.16.4 + name: nvidiadrivers.nvidia.com +spec: + group: nvidia.com + names: + kind: NVIDIADriver + listKind: NVIDIADriverList + plural: nvidiadrivers + shortNames: + - nvd + - nvdriver + - nvdrivers + singular: nvidiadriver + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: Status + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: NVIDIADriver is the Schema for the nvidiadrivers API + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: NVIDIADriverSpec defines the desired state of NVIDIADriver + properties: + annotations: + additionalProperties: + type: string + description: |- + Optional: Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + type: object + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + certConfig: + description: 'Optional: Custom certificates configuration for NVIDIA + Driver container' + properties: + name: + type: string + type: object + driverType: + default: gpu + description: DriverType defines NVIDIA driver type + enum: + - gpu + - vgpu + - vgpu-host-manager + type: string + x-kubernetes-validations: + - message: driverType is an immutable field. Please create a new NvidiaDriver + resource instead when you want to change this setting. + rule: self == oldSelf + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present in + a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + gdrcopy: + description: GDRCopy defines the spec for GDRCopy driver + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if GDRCopy is enabled through GPU + operator + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: GDRCopy driver image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: GDRCopy diver image repository + type: string + version: + description: GDRCopy driver image tag + type: string + type: object + gds: + description: GPUDirectStorage defines the spec for GDS driver + properties: + args: + description: 'Optional: List of arguments' + items: + type: string + type: array + enabled: + description: Enabled indicates if GPUDirect Storage is enabled + through GPU operator + type: boolean + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: NVIDIA GPUDirect Storage Driver image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: NVIDIA GPUDirect Storage Driver image repository + type: string + version: + description: NVIDIA GPUDirect Storage Driver image tag + type: string + type: object + image: + default: nvcr.io/nvidia/driver + description: NVIDIA Driver container image name + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + kernelModuleConfig: + description: 'Optional: Kernel module configuration parameters for + the NVIDIA Driver' + properties: + name: + type: string + type: object + labels: + additionalProperties: + type: string + description: |- + Optional: Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + type: object + licensingConfig: + description: 'Optional: Licensing configuration for NVIDIA vGPU licensing' + properties: + name: + type: string + nlsEnabled: + description: NLSEnabled indicates if NVIDIA Licensing System is + used for licensing. + type: boolean + type: object + livenessProbe: + description: NVIDIA Driver container liveness probe settings + properties: + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + minimum: 1 + type: integer + type: object + manager: + description: Manager represents configuration for NVIDIA Driver Manager + initContainer + properties: + env: + description: 'Optional: List of environment variables' + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. + type: string + value: + description: Value of the environment variable. + type: string + required: + - name + type: object + type: array + image: + description: Image represents NVIDIA Driver Manager image name + pattern: '[a-zA-Z0-9\-]+' + type: string + imagePullPolicy: + description: Image pull policy + type: string + imagePullSecrets: + description: Image pull secrets + items: + type: string + type: array + repository: + description: Repository represents Driver Managerrepository path + type: string + version: + description: Version represents NVIDIA Driver Manager image tag(version) + type: string + type: object + nodeAffinity: + description: Affinity specifies node affinity rules for driver pods + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the corresponding + weight. + properties: + matchExpressions: + description: A list of node selector requirements by + node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by + node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding + nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + x-kubernetes-list-type: atomic + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. The + terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements by + node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + matchFields: + description: A list of node selector requirements by + node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector applies + to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + x-kubernetes-list-type: atomic + required: + - key + - operator + type: object + type: array + x-kubernetes-list-type: atomic + type: object + x-kubernetes-map-type: atomic + type: array + x-kubernetes-list-type: atomic + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + nodeSelector: + additionalProperties: + type: string + description: NodeSelector specifies a selector for installation of + NVIDIA driver + type: object + priorityClassName: + description: 'Optional: Set priorityClassName' + type: string + rdma: + description: GPUDirectRDMA defines the spec for NVIDIA Peer Memory + driver + properties: + enabled: + description: Enabled indicates if GPUDirect RDMA is enabled through + GPU operator + type: boolean + useHostMofed: + description: UseHostMOFED indicates to use MOFED drivers directly + installed on the host to enable GPUDirect RDMA + type: boolean + type: object + readinessProbe: + description: NVIDIA Driver container readiness probe settings + properties: + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + minimum: 1 + type: integer + type: object + repoConfig: + description: 'Optional: Custom repo configuration for NVIDIA Driver + container' + properties: + name: + type: string + type: object + repository: + description: NVIDIA Driver repository + type: string + resources: + description: 'Optional: Define resources requests and limits for each + pod' + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + startupProbe: + description: NVIDIA Driver container startup probe settings + properties: + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + minimum: 1 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + minimum: 1 + type: integer + type: object + tolerations: + description: 'Optional: Set tolerations' + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + useOpenKernelModules: + description: UseOpenKernelModules indicates if the open GPU kernel + modules should be used + type: boolean + usePrecompiled: + description: UsePrecompiled indicates if deployment of NVIDIA Driver + using pre-compiled modules is enabled + type: boolean + x-kubernetes-validations: + - message: usePrecompiled is an immutable field. Please create a new + NvidiaDriver resource instead when you want to change this setting. + rule: self == oldSelf + version: + description: NVIDIA Driver version (or just branch for precompiled + drivers) + type: string + virtualTopologyConfig: + description: 'Optional: Virtual Topology Daemon configuration for + NVIDIA vGPU drivers' + properties: + name: + description: 'Optional: Config name representing virtual topology + daemon configuration file nvidia-topologyd.conf' + type: string + type: object + required: + - driverType + - image + type: object + status: + description: NVIDIADriverStatus defines the observed state of NVIDIADriver + properties: + conditions: + description: Conditions is a list of conditions representing the NVIDIADriver's + current state. + items: + description: Condition contains details for one aspect of the current + state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + namespace: + description: Namespace indicates a namespace in which the operator + and driver are installed + type: string + state: + description: |- + INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + Important: Run "make" to regenerate code after modifying this file + State indicates status of NVIDIADriver instance + enum: + - ignored + - ready + - notReady + type: string + required: + - state + type: object + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/_helpers.tpl b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/_helpers.tpl new file mode 100644 index 000000000..305c9d1fe --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/_helpers.tpl @@ -0,0 +1,80 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "gpu-operator.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "gpu-operator.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gpu-operator.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} + +{{- define "gpu-operator.labels" -}} +app.kubernetes.io/name: {{ include "gpu-operator.name" . }} +helm.sh/chart: {{ include "gpu-operator.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- if .Values.operator.labels }} +{{ toYaml .Values.operator.labels }} +{{- end }} +{{- end -}} + +{{- define "gpu-operator.operand-labels" -}} +helm.sh/chart: {{ include "gpu-operator.chart" . }} +app.kubernetes.io/managed-by: {{ include "gpu-operator.name" . }} +{{- if .Values.daemonsets.labels }} +{{ toYaml .Values.daemonsets.labels }} +{{- end }} +{{- end -}} + +{{- define "gpu-operator.matchLabels" -}} +app.kubernetes.io/name: {{ include "gpu-operator.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Full image name with tag +*/}} +{{- define "gpu-operator.fullimage" -}} +{{- .Values.operator.repository -}}/{{- .Values.operator.image -}}:{{- .Values.operator.version | default .Chart.AppVersion -}} +{{- end }} + +{{/* +Full image name with tag +*/}} +{{- define "driver-manager.fullimage" -}} +{{- .Values.driver.manager.repository -}}/{{- .Values.driver.manager.image -}}:{{- .Values.driver.manager.version -}} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/cleanup_crd.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/cleanup_crd.yaml new file mode 100644 index 000000000..fd0c1b799 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/cleanup_crd.yaml @@ -0,0 +1,45 @@ +{{- if .Values.operator.cleanupCRD }} +apiVersion: batch/v1 +kind: Job +metadata: + name: gpu-operator-cleanup-crd + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-delete + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" +spec: + template: + metadata: + name: gpu-operator-cleanup-crd + labels: + {{- include "gpu-operator.labels" . | nindent 8 }} + app.kubernetes.io/component: "gpu-operator" + spec: + serviceAccountName: gpu-operator + {{- if .Values.operator.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.operator.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + {{- with .Values.operator.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: cleanup-crd + image: {{ include "gpu-operator.fullimage" . }} + imagePullPolicy: {{ .Values.operator.imagePullPolicy }} + command: + - /bin/sh + - -c + - > + kubectl delete clusterpolicy cluster-policy; + kubectl delete crd clusterpolicies.nvidia.com; + + restartPolicy: OnFailure +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterpolicy.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterpolicy.yaml new file mode 100644 index 000000000..af9e87c38 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterpolicy.yaml @@ -0,0 +1,683 @@ +apiVersion: nvidia.com/v1 +kind: ClusterPolicy +metadata: + name: cluster-policy + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" + {{- if .Values.operator.cleanupCRD }} + # CR cleanup is handled during pre-delete hook + # Add below annotation so that helm doesn't attempt to cleanup CR twice + annotations: + "helm.sh/resource-policy": keep + {{- end }} +spec: + hostPaths: + rootFS: {{ .Values.hostPaths.rootFS }} + driverInstallDir: {{ .Values.hostPaths.driverInstallDir }} + operator: + {{- if .Values.operator.defaultRuntime }} + defaultRuntime: {{ .Values.operator.defaultRuntime }} + {{- end }} + {{- if .Values.operator.runtimeClass }} + runtimeClass: {{ .Values.operator.runtimeClass }} + {{- end }} + {{- if .Values.operator.defaultGPUMode }} + defaultGPUMode: {{ .Values.operator.defaultGPUMode }} + {{- end }} + {{- if .Values.operator.initContainer }} + initContainer: + {{- if .Values.operator.initContainer.repository }} + repository: {{ .Values.operator.initContainer.repository }} + {{- end }} + {{- if .Values.operator.initContainer.image }} + image: {{ .Values.operator.initContainer.image }} + {{- end }} + {{- if .Values.operator.initContainer.version }} + version: {{ .Values.operator.initContainer.version | quote }} + {{- end }} + {{- if .Values.operator.initContainer.imagePullPolicy }} + imagePullPolicy: {{ .Values.operator.initContainer.imagePullPolicy }} + {{- end }} + {{- if .Values.operator.initContainer.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.operator.initContainer.imagePullSecrets | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.operator.use_ocp_driver_toolkit }} + use_ocp_driver_toolkit: {{ .Values.operator.use_ocp_driver_toolkit }} + {{- end }} + daemonsets: + labels: + {{- include "gpu-operator.operand-labels" . | nindent 6 }} + {{- if .Values.daemonsets.annotations }} + annotations: {{ toYaml .Values.daemonsets.annotations | nindent 6 }} + {{- end }} + {{- if .Values.daemonsets.tolerations }} + tolerations: {{ toYaml .Values.daemonsets.tolerations | nindent 6 }} + {{- end }} + {{- if .Values.daemonsets.priorityClassName }} + priorityClassName: {{ .Values.daemonsets.priorityClassName }} + {{- end }} + {{- if .Values.daemonsets.updateStrategy }} + updateStrategy: {{ .Values.daemonsets.updateStrategy }} + {{- end }} + {{- if .Values.daemonsets.rollingUpdate }} + rollingUpdate: + maxUnavailable: {{ .Values.daemonsets.rollingUpdate.maxUnavailable | quote }} + {{- end }} + validator: + {{- if .Values.validator.repository }} + repository: {{ .Values.validator.repository }} + {{- end }} + {{- if .Values.validator.image }} + image: {{ .Values.validator.image }} + {{- end }} + version: {{ .Values.validator.version | default .Chart.AppVersion | quote }} + {{- if .Values.validator.imagePullPolicy }} + imagePullPolicy: {{ .Values.validator.imagePullPolicy }} + {{- end }} + {{- if .Values.validator.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.validator.imagePullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.validator.resources }} + resources: {{ toYaml .Values.validator.resources | nindent 6 }} + {{- end }} + {{- if .Values.validator.env }} + env: {{ toYaml .Values.validator.env | nindent 6 }} + {{- end }} + {{- if .Values.validator.args }} + args: {{ toYaml .Values.validator.args | nindent 6 }} + {{- end }} + {{- if .Values.validator.plugin }} + plugin: + {{- if .Values.validator.plugin.env }} + env: {{ toYaml .Values.validator.plugin.env | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.validator.cuda }} + cuda: + {{- if .Values.validator.cuda.env }} + env: {{ toYaml .Values.validator.cuda.env | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.validator.driver }} + driver: + {{- if .Values.validator.driver.env }} + env: {{ toYaml .Values.validator.driver.env | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.validator.toolkit }} + toolkit: + {{- if .Values.validator.toolkit.env }} + env: {{ toYaml .Values.validator.toolkit.env | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.validator.vfioPCI }} + vfioPCI: + {{- if .Values.validator.vfioPCI.env }} + env: {{ toYaml .Values.validator.vfioPCI.env | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.validator.vgpuManager }} + vgpuManager: + {{- if .Values.validator.vgpuManager.env }} + env: {{ toYaml .Values.validator.vgpuManager.env | nindent 8 }} + {{- end }} + {{- end }} + {{- if .Values.validator.vgpuDevices }} + vgpuDevices: + {{- if .Values.validator.vgpuDevices.env }} + env: {{ toYaml .Values.validator.vgpuDevices.env | nindent 8 }} + {{- end }} + {{- end }} + + mig: + {{- if .Values.mig.strategy }} + strategy: {{ .Values.mig.strategy }} + {{- end }} + psa: + enabled: {{ .Values.psa.enabled }} + cdi: + enabled: {{ .Values.cdi.enabled }} + default: {{ .Values.cdi.default }} + driver: + enabled: {{ .Values.driver.enabled }} + useNvidiaDriverCRD: {{ .Values.driver.nvidiaDriverCRD.enabled }} + useOpenKernelModules: {{ .Values.driver.useOpenKernelModules }} + usePrecompiled: {{ .Values.driver.usePrecompiled }} + {{- if .Values.driver.repository }} + repository: {{ .Values.driver.repository }} + {{- end }} + {{- if .Values.driver.image }} + image: {{ .Values.driver.image }} + {{- end }} + {{- if .Values.driver.version }} + version: {{ .Values.driver.version | quote }} + {{- end }} + {{- if .Values.driver.imagePullPolicy }} + imagePullPolicy: {{ .Values.driver.imagePullPolicy }} + {{- end }} + {{- if .Values.driver.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.driver.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.driver.startupProbe }} + startupProbe: {{ toYaml .Values.driver.startupProbe | nindent 6 }} + {{- end }} + {{- if .Values.driver.livenessProbe }} + livenessProbe: {{ toYaml .Values.driver.livenessProbe | nindent 6 }} + {{- end }} + {{- if .Values.driver.readinessProbe }} + readinessProbe: {{ toYaml .Values.driver.readinessProbe | nindent 6 }} + {{- end }} + rdma: + enabled: {{ .Values.driver.rdma.enabled }} + useHostMofed: {{ .Values.driver.rdma.useHostMofed }} + manager: + {{- if .Values.driver.manager.repository }} + repository: {{ .Values.driver.manager.repository }} + {{- end }} + {{- if .Values.driver.manager.image }} + image: {{ .Values.driver.manager.image }} + {{- end }} + {{- if .Values.driver.manager.version }} + version: {{ .Values.driver.manager.version | quote }} + {{- end }} + {{- if .Values.driver.manager.imagePullPolicy }} + imagePullPolicy: {{ .Values.driver.manager.imagePullPolicy }} + {{- end }} + {{- if .Values.driver.manager.env }} + env: {{ toYaml .Values.driver.manager.env | nindent 8 }} + {{- end }} + {{- if .Values.driver.repoConfig }} + repoConfig: {{ toYaml .Values.driver.repoConfig | nindent 6 }} + {{- end }} + {{- if .Values.driver.certConfig }} + certConfig: {{ toYaml .Values.driver.certConfig | nindent 6 }} + {{- end }} + {{- if .Values.driver.licensingConfig }} + licensingConfig: {{ toYaml .Values.driver.licensingConfig | nindent 6 }} + {{- end }} + {{- if .Values.driver.virtualTopology }} + virtualTopology: {{ toYaml .Values.driver.virtualTopology | nindent 6 }} + {{- end }} + {{- if .Values.driver.kernelModuleConfig }} + kernelModuleConfig: {{ toYaml .Values.driver.kernelModuleConfig | nindent 6 }} + {{- end }} + {{- if .Values.driver.resources }} + resources: {{ toYaml .Values.driver.resources | nindent 6 }} + {{- end }} + {{- if .Values.driver.env }} + env: {{ toYaml .Values.driver.env | nindent 6 }} + {{- end }} + {{- if .Values.driver.args }} + args: {{ toYaml .Values.driver.args | nindent 6 }} + {{- end }} + {{- if .Values.driver.upgradePolicy }} + upgradePolicy: + autoUpgrade: {{ .Values.driver.upgradePolicy.autoUpgrade | default false }} + maxParallelUpgrades: {{ .Values.driver.upgradePolicy.maxParallelUpgrades | default 0 }} + maxUnavailable : {{ .Values.driver.upgradePolicy.maxUnavailable | default "25%" }} + waitForCompletion: + timeoutSeconds: {{ .Values.driver.upgradePolicy.waitForCompletion.timeoutSeconds }} + {{- if .Values.driver.upgradePolicy.waitForCompletion.podSelector }} + podSelector: {{ .Values.driver.upgradePolicy.waitForCompletion.podSelector }} + {{- end }} + podDeletion: + force: {{ .Values.driver.upgradePolicy.gpuPodDeletion.force | default false }} + timeoutSeconds: {{ .Values.driver.upgradePolicy.gpuPodDeletion.timeoutSeconds }} + deleteEmptyDir: {{ .Values.driver.upgradePolicy.gpuPodDeletion.deleteEmptyDir | default false }} + drain: + enable: {{ .Values.driver.upgradePolicy.drain.enable | default false }} + force: {{ .Values.driver.upgradePolicy.drain.force | default false }} + {{- if .Values.driver.upgradePolicy.drain.podSelector }} + podSelector: {{ .Values.driver.upgradePolicy.drain.podSelector }} + {{- end }} + timeoutSeconds: {{ .Values.driver.upgradePolicy.drain.timeoutSeconds }} + deleteEmptyDir: {{ .Values.driver.upgradePolicy.drain.deleteEmptyDir | default false}} + {{- end }} + vgpuManager: + enabled: {{ .Values.vgpuManager.enabled }} + {{- if .Values.vgpuManager.repository }} + repository: {{ .Values.vgpuManager.repository }} + {{- end }} + {{- if .Values.vgpuManager.image }} + image: {{ .Values.vgpuManager.image }} + {{- end }} + {{- if .Values.vgpuManager.version }} + version: {{ .Values.vgpuManager.version | quote }} + {{- end }} + {{- if .Values.vgpuManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.vgpuManager.imagePullPolicy }} + {{- end }} + {{- if .Values.vgpuManager.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.vgpuManager.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.vgpuManager.resources }} + resources: {{ toYaml .Values.vgpuManager.resources | nindent 6 }} + {{- end }} + {{- if .Values.vgpuManager.env }} + env: {{ toYaml .Values.vgpuManager.env | nindent 6 }} + {{- end }} + {{- if .Values.vgpuManager.args }} + args: {{ toYaml .Values.vgpuManager.args | nindent 6 }} + {{- end }} + driverManager: + {{- if .Values.vgpuManager.driverManager.repository }} + repository: {{ .Values.vgpuManager.driverManager.repository }} + {{- end }} + {{- if .Values.vgpuManager.driverManager.image }} + image: {{ .Values.vgpuManager.driverManager.image }} + {{- end }} + {{- if .Values.vgpuManager.driverManager.version }} + version: {{ .Values.vgpuManager.driverManager.version | quote }} + {{- end }} + {{- if .Values.vgpuManager.driverManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.vgpuManager.driverManager.imagePullPolicy }} + {{- end }} + {{- if .Values.vgpuManager.driverManager.env }} + env: {{ toYaml .Values.vgpuManager.driverManager.env | nindent 8 }} + {{- end }} + kataManager: + enabled: {{ .Values.kataManager.enabled }} + config: {{ toYaml .Values.kataManager.config | nindent 6 }} + {{- if .Values.kataManager.repository }} + repository: {{ .Values.kataManager.repository }} + {{- end }} + {{- if .Values.kataManager.image }} + image: {{ .Values.kataManager.image }} + {{- end }} + {{- if .Values.kataManager.version }} + version: {{ .Values.kataManager.version | quote }} + {{- end }} + {{- if .Values.kataManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.kataManager.imagePullPolicy }} + {{- end }} + {{- if .Values.kataManager.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.kataManager.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.kataManager.resources }} + resources: {{ toYaml .Values.kataManager.resources | nindent 6 }} + {{- end }} + {{- if .Values.kataManager.env }} + env: {{ toYaml .Values.kataManager.env | nindent 6 }} + {{- end }} + {{- if .Values.kataManager.args }} + args: {{ toYaml .Values.kataManager.args | nindent 6 }} + {{- end }} + vfioManager: + enabled: {{ .Values.vfioManager.enabled }} + {{- if .Values.vfioManager.repository }} + repository: {{ .Values.vfioManager.repository }} + {{- end }} + {{- if .Values.vfioManager.image }} + image: {{ .Values.vfioManager.image }} + {{- end }} + {{- if .Values.vfioManager.version }} + version: {{ .Values.vfioManager.version | quote }} + {{- end }} + {{- if .Values.vfioManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.vfioManager.imagePullPolicy }} + {{- end }} + {{- if .Values.vfioManager.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.vfioManager.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.vfioManager.resources }} + resources: {{ toYaml .Values.vfioManager.resources | nindent 6 }} + {{- end }} + {{- if .Values.vfioManager.env }} + env: {{ toYaml .Values.vfioManager.env | nindent 6 }} + {{- end }} + {{- if .Values.vfioManager.args }} + args: {{ toYaml .Values.vfioManager.args | nindent 6 }} + {{- end }} + driverManager: + {{- if .Values.vfioManager.driverManager.repository }} + repository: {{ .Values.vfioManager.driverManager.repository }} + {{- end }} + {{- if .Values.vfioManager.driverManager.image }} + image: {{ .Values.vfioManager.driverManager.image }} + {{- end }} + {{- if .Values.vfioManager.driverManager.version }} + version: {{ .Values.vfioManager.driverManager.version | quote }} + {{- end }} + {{- if .Values.vfioManager.driverManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.vfioManager.driverManager.imagePullPolicy }} + {{- end }} + {{- if .Values.vfioManager.driverManager.env }} + env: {{ toYaml .Values.vfioManager.driverManager.env | nindent 8 }} + {{- end }} + vgpuDeviceManager: + enabled: {{ .Values.vgpuDeviceManager.enabled }} + {{- if .Values.vgpuDeviceManager.repository }} + repository: {{ .Values.vgpuDeviceManager.repository }} + {{- end }} + {{- if .Values.vgpuDeviceManager.image }} + image: {{ .Values.vgpuDeviceManager.image }} + {{- end }} + {{- if .Values.vgpuDeviceManager.version }} + version: {{ .Values.vgpuDeviceManager.version | quote }} + {{- end }} + {{- if .Values.vgpuDeviceManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.vgpuDeviceManager.imagePullPolicy }} + {{- end }} + {{- if .Values.vgpuDeviceManager.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.vgpuDeviceManager.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.vgpuDeviceManager.resources }} + resources: {{ toYaml .Values.vgpuDeviceManager.resources | nindent 6 }} + {{- end }} + {{- if .Values.vgpuDeviceManager.env }} + env: {{ toYaml .Values.vgpuDeviceManager.env | nindent 6 }} + {{- end }} + {{- if .Values.vgpuDeviceManager.args }} + args: {{ toYaml .Values.vgpuDeviceManager.args | nindent 6 }} + {{- end }} + {{- if .Values.vgpuDeviceManager.config }} + config: {{ toYaml .Values.vgpuDeviceManager.config | nindent 6 }} + {{- end }} + ccManager: + enabled: {{ .Values.ccManager.enabled }} + defaultMode: {{ .Values.ccManager.defaultMode | quote }} + {{- if .Values.ccManager.repository }} + repository: {{ .Values.ccManager.repository }} + {{- end }} + {{- if .Values.ccManager.image }} + image: {{ .Values.ccManager.image }} + {{- end }} + {{- if .Values.ccManager.version }} + version: {{ .Values.ccManager.version | quote }} + {{- end }} + {{- if .Values.ccManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.ccManager.imagePullPolicy }} + {{- end }} + {{- if .Values.ccManager.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.ccManager.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.ccManager.resources }} + resources: {{ toYaml .Values.ccManager.resources | nindent 6 }} + {{- end }} + {{- if .Values.ccManager.env }} + env: {{ toYaml .Values.vfioManager.env | nindent 6 }} + {{- end }} + {{- if .Values.ccManager.args }} + args: {{ toYaml .Values.ccManager.args | nindent 6 }} + {{- end }} + toolkit: + enabled: {{ .Values.toolkit.enabled }} + {{- if .Values.toolkit.repository }} + repository: {{ .Values.toolkit.repository }} + {{- end }} + {{- if .Values.toolkit.image }} + image: {{ .Values.toolkit.image }} + {{- end }} + {{- if .Values.toolkit.version }} + version: {{ .Values.toolkit.version | quote }} + {{- end }} + {{- if .Values.toolkit.imagePullPolicy }} + imagePullPolicy: {{ .Values.toolkit.imagePullPolicy }} + {{- end }} + {{- if .Values.toolkit.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.toolkit.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.toolkit.resources }} + resources: {{ toYaml .Values.toolkit.resources | nindent 6 }} + {{- end }} + {{- if .Values.toolkit.env }} + env: {{ toYaml .Values.toolkit.env | nindent 6 }} + {{- end }} + {{- if .Values.toolkit.installDir }} + installDir: {{ .Values.toolkit.installDir }} + {{- end }} + devicePlugin: + enabled: {{ .Values.devicePlugin.enabled }} + {{- if .Values.devicePlugin.repository }} + repository: {{ .Values.devicePlugin.repository }} + {{- end }} + {{- if .Values.devicePlugin.image }} + image: {{ .Values.devicePlugin.image }} + {{- end }} + {{- if .Values.devicePlugin.version }} + version: {{ .Values.devicePlugin.version | quote }} + {{- end }} + {{- if .Values.devicePlugin.imagePullPolicy }} + imagePullPolicy: {{ .Values.devicePlugin.imagePullPolicy }} + {{- end }} + {{- if .Values.devicePlugin.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.devicePlugin.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.devicePlugin.resources }} + resources: {{ toYaml .Values.devicePlugin.resources | nindent 6 }} + {{- end }} + {{- if .Values.devicePlugin.env }} + env: {{ toYaml .Values.devicePlugin.env | nindent 6 }} + {{- end }} + {{- if .Values.devicePlugin.args }} + args: {{ toYaml .Values.devicePlugin.args | nindent 6 }} + {{- end }} + {{- if .Values.devicePlugin.config.name }} + config: + name: {{ .Values.devicePlugin.config.name }} + default: {{ .Values.devicePlugin.config.default }} + {{- end }} + dcgm: + enabled: {{ .Values.dcgm.enabled }} + {{- if .Values.dcgm.repository }} + repository: {{ .Values.dcgm.repository }} + {{- end }} + {{- if .Values.dcgm.image }} + image: {{ .Values.dcgm.image }} + {{- end }} + {{- if .Values.dcgm.version }} + version: {{ .Values.dcgm.version | quote }} + {{- end }} + {{- if .Values.dcgm.imagePullPolicy }} + imagePullPolicy: {{ .Values.dcgm.imagePullPolicy }} + {{- end }} + {{- if .Values.dcgm.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.dcgm.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.dcgm.resources }} + resources: {{ toYaml .Values.dcgm.resources | nindent 6 }} + {{- end }} + {{- if .Values.dcgm.env }} + env: {{ toYaml .Values.dcgm.env | nindent 6 }} + {{- end }} + {{- if .Values.dcgm.args }} + args: {{ toYaml .Values.dcgm.args | nindent 6 }} + {{- end }} + dcgmExporter: + enabled: {{ .Values.dcgmExporter.enabled }} + {{- if .Values.dcgmExporter.repository }} + repository: {{ .Values.dcgmExporter.repository }} + {{- end }} + {{- if .Values.dcgmExporter.image }} + image: {{ .Values.dcgmExporter.image }} + {{- end }} + {{- if .Values.dcgmExporter.version }} + version: {{ .Values.dcgmExporter.version | quote }} + {{- end }} + {{- if .Values.dcgmExporter.imagePullPolicy }} + imagePullPolicy: {{ .Values.dcgmExporter.imagePullPolicy }} + {{- end }} + {{- if .Values.dcgmExporter.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.dcgmExporter.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.dcgmExporter.resources }} + resources: {{ toYaml .Values.dcgmExporter.resources | nindent 6 }} + {{- end }} + {{- if .Values.dcgmExporter.env }} + env: {{ toYaml .Values.dcgmExporter.env | nindent 6 }} + {{- end }} + {{- if .Values.dcgmExporter.args }} + args: {{ toYaml .Values.dcgmExporter.args | nindent 6 }} + {{- end }} + {{- if and (.Values.dcgmExporter.config) (.Values.dcgmExporter.config.name) }} + config: + name: {{ .Values.dcgmExporter.config.name }} + {{- end }} + {{- if .Values.dcgmExporter.serviceMonitor }} + serviceMonitor: {{ toYaml .Values.dcgmExporter.serviceMonitor | nindent 6 }} + {{- end }} + gfd: + enabled: {{ .Values.gfd.enabled }} + {{- if .Values.gfd.repository }} + repository: {{ .Values.gfd.repository }} + {{- end }} + {{- if .Values.gfd.image }} + image: {{ .Values.gfd.image }} + {{- end }} + {{- if .Values.gfd.version }} + version: {{ .Values.gfd.version | quote }} + {{- end }} + {{- if .Values.gfd.imagePullPolicy }} + imagePullPolicy: {{ .Values.gfd.imagePullPolicy }} + {{- end }} + {{- if .Values.gfd.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.gfd.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.gfd.resources }} + resources: {{ toYaml .Values.gfd.resources | nindent 6 }} + {{- end }} + {{- if .Values.gfd.env }} + env: {{ toYaml .Values.gfd.env | nindent 6 }} + {{- end }} + {{- if .Values.gfd.args }} + args: {{ toYaml .Values.gfd.args | nindent 6 }} + {{- end }} + migManager: + enabled: {{ .Values.migManager.enabled }} + {{- if .Values.migManager.repository }} + repository: {{ .Values.migManager.repository }} + {{- end }} + {{- if .Values.migManager.image }} + image: {{ .Values.migManager.image }} + {{- end }} + {{- if .Values.migManager.version }} + version: {{ .Values.migManager.version | quote }} + {{- end }} + {{- if .Values.migManager.imagePullPolicy }} + imagePullPolicy: {{ .Values.migManager.imagePullPolicy }} + {{- end }} + {{- if .Values.migManager.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.migManager.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.migManager.resources }} + resources: {{ toYaml .Values.migManager.resources | nindent 6 }} + {{- end }} + {{- if .Values.migManager.env }} + env: {{ toYaml .Values.migManager.env | nindent 6 }} + {{- end }} + {{- if .Values.migManager.args }} + args: {{ toYaml .Values.migManager.args | nindent 6 }} + {{- end }} + {{- if .Values.migManager.config }} + config: + name: {{ .Values.migManager.config.name }} + default: {{ .Values.migManager.config.default }} + {{- end }} + {{- if .Values.migManager.gpuClientsConfig }} + gpuClientsConfig: {{ toYaml .Values.migManager.gpuClientsConfig | nindent 6 }} + {{- end }} + nodeStatusExporter: + enabled: {{ .Values.nodeStatusExporter.enabled }} + {{- if .Values.nodeStatusExporter.repository }} + repository: {{ .Values.nodeStatusExporter.repository }} + {{- end }} + {{- if .Values.nodeStatusExporter.image }} + image: {{ .Values.nodeStatusExporter.image }} + {{- end }} + version: {{ .Values.nodeStatusExporter.version | default .Chart.AppVersion | quote }} + {{- if .Values.nodeStatusExporter.imagePullPolicy }} + imagePullPolicy: {{ .Values.nodeStatusExporter.imagePullPolicy }} + {{- end }} + {{- if .Values.nodeStatusExporter.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.nodeStatusExporter.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.nodeStatusExporter.resources }} + resources: {{ toYaml .Values.nodeStatusExporter.resources | nindent 6 }} + {{- end }} + {{- if .Values.nodeStatusExporter.env }} + env: {{ toYaml .Values.nodeStatusExporter.env | nindent 6 }} + {{- end }} + {{- if .Values.nodeStatusExporter.args }} + args: {{ toYaml .Values.nodeStatusExporter.args | nindent 6 }} + {{- end }} + {{- if .Values.gds.enabled }} + gds: + enabled: {{ .Values.gds.enabled }} + {{- if .Values.gds.repository }} + repository: {{ .Values.gds.repository }} + {{- end }} + {{- if .Values.gds.image }} + image: {{ .Values.gds.image }} + {{- end }} + version: {{ .Values.gds.version | quote }} + {{- if .Values.gds.imagePullPolicy }} + imagePullPolicy: {{ .Values.gds.imagePullPolicy }} + {{- end }} + {{- if .Values.gds.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.gds.imagePullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.gds.env }} + env: {{ toYaml .Values.gds.env | nindent 6 }} + {{- end }} + {{- if .Values.gds.args }} + args: {{ toYaml .Values.gds.args | nindent 6 }} + {{- end }} + {{- end }} + {{- if .Values.gdrcopy }} + gdrcopy: + enabled: {{ .Values.gdrcopy.enabled | default false }} + {{- if .Values.gdrcopy.repository }} + repository: {{ .Values.gdrcopy.repository }} + {{- end }} + {{- if .Values.gdrcopy.image }} + image: {{ .Values.gdrcopy.image }} + {{- end }} + version: {{ .Values.gdrcopy.version | quote }} + {{- if .Values.gdrcopy.imagePullPolicy }} + imagePullPolicy: {{ .Values.gdrcopy.imagePullPolicy }} + {{- end }} + {{- if .Values.gdrcopy.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.gdrcopy.imagePullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.gdrcopy.env }} + env: {{ toYaml .Values.gdrcopy.env | nindent 6 }} + {{- end }} + {{- if .Values.gdrcopy.args }} + args: {{ toYaml .Values.gdrcopy.args | nindent 6 }} + {{- end }} + {{- end }} + sandboxWorkloads: + enabled: {{ .Values.sandboxWorkloads.enabled }} + {{- if .Values.sandboxWorkloads.defaultWorkload }} + defaultWorkload: {{ .Values.sandboxWorkloads.defaultWorkload }} + {{- end }} + sandboxDevicePlugin: + {{- if .Values.sandboxDevicePlugin.enabled }} + enabled: {{ .Values.sandboxDevicePlugin.enabled }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.repository }} + repository: {{ .Values.sandboxDevicePlugin.repository }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.image }} + image: {{ .Values.sandboxDevicePlugin.image }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.version }} + version: {{ .Values.sandboxDevicePlugin.version | quote }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.imagePullPolicy }} + imagePullPolicy: {{ .Values.sandboxDevicePlugin.imagePullPolicy }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.sandboxDevicePlugin.imagePullSecrets | nindent 6 }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.resources }} + resources: {{ toYaml .Values.sandboxDevicePlugin.resources | nindent 6 }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.env }} + env: {{ toYaml .Values.sandboxDevicePlugin.env | nindent 6 }} + {{- end }} + {{- if .Values.sandboxDevicePlugin.args }} + args: {{ toYaml .Values.sandboxDevicePlugin.args | nindent 6 }} + {{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrole.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrole.yaml new file mode 100644 index 000000000..4acbcf29c --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrole.yaml @@ -0,0 +1,146 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gpu-operator + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" +rules: +- apiGroups: + - config.openshift.io + resources: + - clusterversions + - proxies + verbs: + - get + - list + - watch +- apiGroups: + - image.openshift.io + resources: + - imagestreams + verbs: + - get + - list + - watch +- apiGroups: + - security.openshift.io + resources: + - securitycontextconstraints + verbs: + - create + - get + - list + - watch + - update + - patch + - delete + - use +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + - clusterrolebindings + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - nodes + verbs: + - get + - list + - watch + - update + - patch +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - create + - watch + - update + - patch +- apiGroups: + - "" + resources: + - events + - pods + - pods/eviction + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - apps + resources: + - daemonsets + verbs: + - get + - list + - watch +- apiGroups: + - nvidia.com + resources: + - clusterpolicies + - clusterpolicies/finalizers + - clusterpolicies/status + - nvidiadrivers + - nvidiadrivers/finalizers + - nvidiadrivers/status + verbs: + - create + - get + - list + - watch + - update + - patch + - delete + - deletecollection +- apiGroups: + - scheduling.k8s.io + resources: + - priorityclasses + verbs: + - get + - list + - watch + - create +- apiGroups: + - node.k8s.io + resources: + - runtimeclasses + verbs: + - get + - list + - create + - update + - watch + - delete +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - get + - list + - watch + - update + - patch + - create +{{- if .Values.operator.cleanupCRD }} + - delete +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrolebinding.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrolebinding.yaml new file mode 100644 index 000000000..08b87fbce --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: gpu-operator + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" +subjects: +- kind: ServiceAccount + name: gpu-operator + namespace: {{ $.Release.Namespace }} +- kind: ServiceAccount + name: node-feature-discovery + namespace: {{ $.Release.Namespace }} +roleRef: + kind: ClusterRole + name: gpu-operator + apiGroup: rbac.authorization.k8s.io diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/dcgm_exporter_config.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/dcgm_exporter_config.yaml new file mode 100644 index 000000000..c4bf6dcc8 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/dcgm_exporter_config.yaml @@ -0,0 +1,14 @@ +{{- if .Values.dcgmExporter.config }} +{{- if and (.Values.dcgmExporter.config.create) (not (empty .Values.dcgmExporter.config.data)) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.dcgmExporter.config.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} +data: + dcgm-metrics.csv: | +{{- .Values.dcgmExporter.config.data | nindent 4 }} +{{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/mig_config.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/mig_config.yaml new file mode 100644 index 000000000..2ceb04779 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/mig_config.yaml @@ -0,0 +1,10 @@ +{{- if and (.Values.migManager.config.create) (not (empty .Values.migManager.config.data)) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.migManager.config.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} +data: {{ toYaml .Values.migManager.config.data | nindent 2 }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nodefeaturerules.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nodefeaturerules.yaml new file mode 100644 index 000000000..6076b3d31 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nodefeaturerules.yaml @@ -0,0 +1,107 @@ +{{- if .Values.nfd.nodefeaturerules }} +apiVersion: nfd.k8s-sigs.io/v1alpha1 +kind: NodeFeatureRule +metadata: + name: nvidia-nfd-nodefeaturerules +spec: + rules: + - name: "TDX rule" + labels: + tdx.enabled: "true" + matchFeatures: + - feature: cpu.security + matchExpressions: + tdx.enabled: {op: IsTrue} + - name: "TDX total keys rule" + extendedResources: + tdx.total_keys: "@cpu.security.tdx.total_keys" + matchFeatures: + - feature: cpu.security + matchExpressions: + tdx.enabled: {op: IsTrue} + - name: "SEV-SNP rule" + labels: + sev.snp.enabled: "true" + matchFeatures: + - feature: cpu.security + matchExpressions: + sev.snp.enabled: + op: IsTrue + - name: "SEV-ES rule" + labels: + sev.es.enabled: "true" + matchFeatures: + - feature: cpu.security + matchExpressions: + sev.es.enabled: + op: IsTrue + - name: SEV system capacities + extendedResources: + sev_asids: '@cpu.security.sev.asids' + sev_es: '@cpu.security.sev.encrypted_state_ids' + matchFeatures: + - feature: cpu.security + matchExpressions: + sev.enabled: + op: Exists + - name: "NVIDIA H100" + labels: + "nvidia.com/gpu.H100": "true" + "nvidia.com/gpu.family": "hopper" + matchFeatures: + - feature: pci.device + matchExpressions: + vendor: {op: In, value: ["10de"]} + device: {op: In, value: ["2339"]} + - name: "NVIDIA H100 PCIe" + labels: + "nvidia.com/gpu.H100.pcie": "true" + "nvidia.com/gpu.family": "hopper" + matchFeatures: + - feature: pci.device + matchExpressions: + vendor: {op: In, value: ["10de"]} + device: {op: In, value: ["2331"]} + - name: "NVIDIA H100 80GB HBM3" + labels: + "nvidia.com/gpu.H100.HBM3": "true" + "nvidia.com/gpu.family": "hopper" + matchFeatures: + - feature: pci.device + matchExpressions: + vendor: {op: In, value: ["10de"]} + device: {op: In, value: ["2330"]} + - name: "NVIDIA H800" + labels: + "nvidia.com/gpu.H800": "true" + "nvidia.com/gpu.family": "hopper" + matchFeatures: + - feature: pci.device + matchExpressions: + vendor: {op: In, value: ["10de"]} + device: {op: In, value: ["2324"]} + - name: "NVIDIA H800 PCIE" + labels: + "nvidia.com/gpu.H800.pcie": "true" + "nvidia.com/gpu.family": "hopper" + matchFeatures: + - feature: pci.device + matchExpressions: + vendor: {op: In, value: ["10de"]} + device: {op: In, value: ["2322"]} + - name: "NVIDIA CC Enabled" + labels: + "nvidia.com/cc.capable": "true" + matchAny: # TDX/SEV + Hopper GPU + - matchFeatures: + - feature: rule.matched + matchExpressions: + nvidia.com/gpu.family: {op: In, value: ["hopper"]} + sev.snp.enabled: {op: IsTrue} + - matchFeatures: + - feature: rule.matched + matchExpressions: + nvidia.com/gpu.family: {op: In, value: ["hopper"]} + tdx.enabled: {op: IsTrue} +{{- end }} + diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nvidiadriver.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nvidiadriver.yaml new file mode 100644 index 000000000..31660c025 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/nvidiadriver.yaml @@ -0,0 +1,119 @@ +{{- if and .Values.driver.nvidiaDriverCRD.enabled .Values.driver.nvidiaDriverCRD.deployDefaultCR }} +apiVersion: nvidia.com/v1alpha1 +kind: NVIDIADriver +metadata: + name: default +spec: + repository: {{ .Values.driver.repository }} + image: {{ .Values.driver.image }} + version: {{ .Values.driver.version }} + useOpenKernelModules: {{ .Values.driver.useOpenKernelModules }} + usePrecompiled: {{ .Values.driver.usePrecompiled }} + driverType: {{ .Values.driver.nvidiaDriverCRD.driverType | default "gpu" }} + {{- if .Values.daemonsets.annotations }} + annotations: {{ toYaml .Values.daemonsets.annotations | nindent 6 }} + {{- end }} + {{- if .Values.daemonsets.labels }} + labels: {{ toYaml .Values.daemonsets.labels | nindent 6 }} + {{- end }} + {{- if .Values.driver.nvidiaDriverCRD.nodeSelector }} + nodeSelector: {{ toYaml .Values.driver.nvidiaDriverCRD.nodeSelector | nindent 6 }} + {{- end }} + {{- if .Values.driver.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.driver.imagePullSecrets | nindent 4 }} + {{- end }} + {{- if .Values.driver.manager }} + manager: {{ toYaml .Values.driver.manager | nindent 4 }} + {{- end }} + {{- if .Values.driver.startupProbe }} + startupProbe: {{ toYaml .Values.driver.startupProbe | nindent 4 }} + {{- end }} + {{- if .Values.driver.livenessProbe }} + livenessProbe: {{ toYaml .Values.driver.livenessProbe | nindent 4 }} + {{- end }} + {{- if .Values.driver.readinessProbe }} + readinessProbe: {{ toYaml .Values.driver.readinessProbe | nindent 4 }} + {{- end }} + rdma: + enabled: {{ .Values.driver.rdma.enabled }} + useHostMofed: {{ .Values.driver.rdma.useHostMofed }} + {{- if .Values.daemonsets.tolerations }} + tolerations: {{ toYaml .Values.daemonsets.tolerations | nindent 6 }} + {{- end }} + {{- if .Values.driver.repoConfig.configMapName }} + repoConfig: + name: {{ .Values.driver.repoConfig.configMapName }} + {{- end }} + {{- if .Values.driver.certConfig.name }} + certConfig: + name: {{ .Values.driver.certConfig.name }} + {{- end }} + {{- if .Values.driver.licensingConfig.configMapName }} + licensingConfig: + name: {{ .Values.driver.licensingConfig.configMapName }} + nlsEnabled: {{ .Values.driver.licensingConfig.nlsEnabled | default true }} + {{- end }} + {{- if .Values.driver.virtualTopology.config }} + virtualTopologyConfig: + name: {{ .Values.driver.virtualTopology.config }} + {{- end }} + {{- if .Values.driver.kernelModuleConfig.name }} + kernelModuleConfig: + name: {{ .Values.driver.kernelModuleConfig.name }} + {{- end }} + {{- if .Values.driver.resources }} + resources: {{ toYaml .Values.driver.resources | nindent 6 }} + {{- end }} + {{- if .Values.driver.env }} + env: {{ toYaml .Values.driver.env | nindent 6 }} + {{- end }} + {{- if .Values.driver.args }} + args: {{ toYaml .Values.driver.args | nindent 6 }} + {{- end }} + {{- if .Values.gds.enabled }} + gds: + enabled: {{ .Values.gds.enabled }} + {{- if .Values.gds.repository }} + repository: {{ .Values.gds.repository }} + {{- end }} + {{- if .Values.gds.image }} + image: {{ .Values.gds.image }} + {{- end }} + version: {{ .Values.gds.version | quote }} + {{- if .Values.gds.imagePullPolicy }} + imagePullPolicy: {{ .Values.gds.imagePullPolicy }} + {{- end }} + {{- if .Values.gds.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.gds.imagePullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.gds.env }} + env: {{ toYaml .Values.gds.env | nindent 6 }} + {{- end }} + {{- if .Values.gds.args }} + args: {{ toYaml .Values.gds.args | nindent 6 }} + {{- end }} + {{- end }} + {{- if .Values.gdrcopy }} + gdrcopy: + enabled: {{ .Values.gdrcopy.enabled | default false }} + {{- if .Values.gdrcopy.repository }} + repository: {{ .Values.gdrcopy.repository }} + {{- end }} + {{- if .Values.gdrcopy.image }} + image: {{ .Values.gdrcopy.image }} + {{- end }} + version: {{ .Values.gdrcopy.version | quote }} + {{- if .Values.gdrcopy.imagePullPolicy }} + imagePullPolicy: {{ .Values.gdrcopy.imagePullPolicy }} + {{- end }} + {{- if .Values.gdrcopy.imagePullSecrets }} + imagePullSecrets: {{ toYaml .Values.gdrcopy.imagePullSecrets | nindent 8 }} + {{- end }} + {{- if .Values.gdrcopy.env }} + env: {{ toYaml .Values.gdrcopy.env | nindent 6 }} + {{- end }} + {{- if .Values.gdrcopy.args }} + args: {{ toYaml .Values.gdrcopy.args | nindent 6 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/operator.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/operator.yaml new file mode 100644 index 000000000..6f4848263 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/operator.yaml @@ -0,0 +1,99 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gpu-operator + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" + nvidia.com/gpu-driver-upgrade-drain.skip: "true" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: "gpu-operator" + app: "gpu-operator" + template: + metadata: + labels: + {{- include "gpu-operator.labels" . | nindent 8 }} + app.kubernetes.io/component: "gpu-operator" + app: "gpu-operator" + nvidia.com/gpu-driver-upgrade-drain.skip: "true" + annotations: + {{- toYaml .Values.operator.annotations | nindent 8 }} + spec: + serviceAccountName: gpu-operator + {{- if .Values.operator.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.operator.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + {{- if .Values.operator.priorityClassName }} + priorityClassName: {{ .Values.operator.priorityClassName }} + {{- end }} + containers: + - name: gpu-operator + image: {{ include "gpu-operator.fullimage" . }} + imagePullPolicy: {{ .Values.operator.imagePullPolicy }} + command: ["gpu-operator"] + args: + - --leader-elect + {{- if .Values.operator.logging.develMode }} + - --zap-devel + {{- else }} + {{- if .Values.operator.logging.timeEncoding }} + - --zap-time-encoding={{- .Values.operator.logging.timeEncoding }} + {{- end }} + {{- if .Values.operator.logging.level }} + - --zap-log-level={{- .Values.operator.logging.level }} + {{- end }} + {{- end }} + env: + - name: WATCH_NAMESPACE + value: "" + - name: OPERATOR_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: "DRIVER_MANAGER_IMAGE" + value: "{{ include "driver-manager.fullimage" . }}" + volumeMounts: + - name: host-os-release + mountPath: "/host-etc/os-release" + readOnly: true + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + {{- with .Values.operator.resources }} + resources: + {{- toYaml . | nindent 10 }} + {{- end }} + ports: + - name: metrics + containerPort: 8080 + volumes: + - name: host-os-release + hostPath: + path: "/etc/os-release" + {{- with .Values.operator.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.operator.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/plugin_config.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/plugin_config.yaml new file mode 100644 index 000000000..21c2d9ab2 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/plugin_config.yaml @@ -0,0 +1,11 @@ +{{- if and (.Values.devicePlugin.config.create) (not (empty .Values.devicePlugin.config.data)) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.devicePlugin.config.name }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} +data: {{ toYaml .Values.devicePlugin.config.data | nindent 2 }} +{{- end }} + \ No newline at end of file diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/readonlyfs_scc.openshift.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/readonlyfs_scc.openshift.yaml new file mode 100644 index 000000000..ff492d3d2 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/readonlyfs_scc.openshift.yaml @@ -0,0 +1,49 @@ +{{- if .Values.platform.openshift }} +apiVersion: security.openshift.io/v1 +kind: SecurityContextConstraints +metadata: + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" + annotations: + kubernetes.io/description: restricted denies access to all host features and requires + pods to be run with a UID, read-only root filesystem and SELinux context that are + allocated to the namespace. This SCC is more restrictive than the default + restrictive SCC and it is used by default for authenticated users and operators and operands. + name: restricted-readonly +allowHostDirVolumePlugin: false +allowHostIPC: false +allowHostNetwork: false +allowHostPID: false +allowHostPorts: false +allowPrivilegeEscalation: true +allowPrivilegedContainer: false +allowedCapabilities: [] +defaultAddCapabilities: [] +fsGroup: + type: MustRunAs +groups: +- system:authenticated +priority: 0 +readOnlyRootFilesystem: true +requiredDropCapabilities: +- KILL +- MKNOD +- SETUID +- SETGID +runAsUser: + type: MustRunAsRange +seLinuxContext: + type: MustRunAs +supplementalGroups: + type: RunAsAny +users: +- system:serviceaccount:{{ $.Release.Namespace }}:gpu-operator +volumes: +- configMap +- downwardAPI +- emptyDir +- persistentVolumeClaim +- projected +- secret +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/role.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/role.yaml new file mode 100644 index 000000000..9e5bcede3 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/role.yaml @@ -0,0 +1,84 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: gpu-operator + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" +rules: +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + - rolebindings + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - apps + resources: + - controllerrevisions + verbs: + - get + - list + - watch +- apiGroups: + - apps + resources: + - daemonsets + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - "" + resources: + - configmaps + - endpoints + - pods + - pods/eviction + - secrets + - services + - services/finalizers + - serviceaccounts + verbs: + - create + - get + - list + - watch + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - monitoring.coreos.com + resources: + - servicemonitors + - prometheusrules + verbs: + - get + - list + - create + - watch + - update + - delete diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/rolebinding.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/rolebinding.yaml new file mode 100644 index 000000000..c915a4659 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/rolebinding.yaml @@ -0,0 +1,15 @@ +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: gpu-operator + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" +subjects: +- kind: ServiceAccount + name: gpu-operator + namespace: {{ $.Release.Namespace }} +roleRef: + kind: Role + name: gpu-operator + apiGroup: rbac.authorization.k8s.io diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/serviceaccount.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/serviceaccount.yaml new file mode 100644 index 000000000..50555e53b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/serviceaccount.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: gpu-operator + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/upgrade_crd.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/upgrade_crd.yaml new file mode 100644 index 000000000..6552558af --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/templates/upgrade_crd.yaml @@ -0,0 +1,95 @@ +{{- if .Values.operator.upgradeCRD }} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: gpu-operator-upgrade-crd-hook-sa + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + helm.sh/hook-weight: "0" +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: gpu-operator-upgrade-crd-hook-role + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + helm.sh/hook-weight: "0" +rules: + - apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - create + - get + - list + - watch + - patch + - update +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: gpu-operator-upgrade-crd-hook-binding + annotations: + helm.sh/hook: pre-upgrade + helm.sh/hook-delete-policy: hook-succeeded,before-hook-creation + helm.sh/hook-weight: "0" +subjects: + - kind: ServiceAccount + name: gpu-operator-upgrade-crd-hook-sa + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: gpu-operator-upgrade-crd-hook-role + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: gpu-operator-upgrade-crd + namespace: {{ .Release.Namespace }} + annotations: + "helm.sh/hook": pre-upgrade + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": hook-succeeded,before-hook-creation + labels: + {{- include "gpu-operator.labels" . | nindent 4 }} + app.kubernetes.io/component: "gpu-operator" +spec: + template: + metadata: + name: gpu-operator-upgrade-crd + labels: + {{- include "gpu-operator.labels" . | nindent 8 }} + app.kubernetes.io/component: "gpu-operator" + spec: + serviceAccountName: gpu-operator-upgrade-crd-hook-sa + {{- if .Values.operator.imagePullSecrets }} + imagePullSecrets: + {{- range .Values.operator.imagePullSecrets }} + - name: {{ . }} + {{- end }} + {{- end }} + {{- with .Values.operator.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + containers: + - name: upgrade-crd + image: {{ include "gpu-operator.fullimage" . }} + imagePullPolicy: {{ .Values.operator.imagePullPolicy }} + command: + - /bin/sh + - -c + - > + kubectl apply -f /opt/gpu-operator/nvidia.com_clusterpolicies.yaml; + kubectl apply -f /opt/gpu-operator/nvidia.com_nvidiadrivers.yaml; + {{- if .Values.nfd.enabled }} + kubectl apply -f /opt/gpu-operator/nfd-api-crds.yaml; + {{- end }} + restartPolicy: OnFailure +{{- end }} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/values.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/values.yaml new file mode 100644 index 000000000..cfddca21b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/gpu-operator/values.yaml @@ -0,0 +1,602 @@ +# Default values for gpu-operator. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +platform: + openshift: false + +nfd: + enabled: true + nodefeaturerules: false + +psa: + enabled: false + +cdi: + enabled: false + default: false + +sandboxWorkloads: + enabled: false + defaultWorkload: "container" + +hostPaths: + # rootFS represents the path to the root filesystem of the host. + # This is used by components that need to interact with the host filesystem + # and as such this must be a chroot-able filesystem. + # Examples include the MIG Manager and Toolkit Container which may need to + # stop, start, or restart systemd services + rootFS: "/" + + # driverInstallDir represents the root at which driver files including libraries, + # config files, and executables can be found. + driverInstallDir: "/run/nvidia/driver" + +daemonsets: + labels: {} + annotations: {} + priorityClassName: system-node-critical + tolerations: + - key: nvidia.com/gpu + operator: Exists + effect: NoSchedule + # configuration for controlling update strategy("OnDelete" or "RollingUpdate") of GPU Operands + # note that driver Daemonset is always set with OnDelete to avoid unintended disruptions + updateStrategy: "RollingUpdate" + # configuration for controlling rolling update of GPU Operands + rollingUpdate: + # maximum number of nodes to simultaneously apply pod updates on. + # can be specified either as number or percentage of nodes. Default 1. + maxUnavailable: "1" + +validator: + repository: nvcr.io/nvidia/cloud-native + image: gpu-operator-validator + # If version is not specified, then default is to use chart.AppVersion + #version: "" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + args: [] + resources: {} + plugin: + env: + - name: WITH_WORKLOAD + value: "false" + +operator: + repository: nvcr.io/nvidia + image: gpu-operator + # If version is not specified, then default is to use chart.AppVersion + #version: "" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + priorityClassName: system-node-critical + defaultRuntime: docker + runtimeClass: nvidia + use_ocp_driver_toolkit: false + # cleanup CRD on chart un-install + cleanupCRD: false + # upgrade CRD on chart upgrade, requires --disable-openapi-validation flag + # to be passed during helm upgrade. + upgradeCRD: true + initContainer: + image: cuda + repository: nvcr.io/nvidia + version: 12.6.3-base-ubi9 + imagePullPolicy: IfNotPresent + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Equal" + value: "" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Equal" + value: "" + effect: "NoSchedule" + annotations: + openshift.io/scc: restricted-readonly + affinity: + nodeAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 1 + preference: + matchExpressions: + - key: "node-role.kubernetes.io/master" + operator: In + values: [""] + - weight: 1 + preference: + matchExpressions: + - key: "node-role.kubernetes.io/control-plane" + operator: In + values: [""] + logging: + # Zap time encoding (one of 'epoch', 'millis', 'nano', 'iso8601', 'rfc3339' or 'rfc3339nano') + timeEncoding: epoch + # Zap Level to configure the verbosity of logging. Can be one of 'debug', 'info', 'error', or any integer value > 0 which corresponds to custom debug levels of increasing verbosity + level: info + # Development Mode defaults(encoder=consoleEncoder,logLevel=Debug,stackTraceLevel=Warn) + # Production Mode defaults(encoder=jsonEncoder,logLevel=Info,stackTraceLevel=Error) + develMode: false + resources: + limits: + cpu: 500m + memory: 350Mi + requests: + cpu: 200m + memory: 100Mi + +mig: + strategy: single + +driver: + enabled: true + nvidiaDriverCRD: + enabled: false + deployDefaultCR: true + driverType: gpu + nodeSelector: {} + useOpenKernelModules: false + # use pre-compiled packages for NVIDIA driver installation. + # only supported for as a tech-preview feature on ubuntu22.04 kernels. + usePrecompiled: false + repository: nvcr.io/nvidia + image: driver + version: "550.144.03" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + startupProbe: + initialDelaySeconds: 60 + periodSeconds: 10 + # nvidia-smi can take longer than 30s in some cases + # ensure enough timeout is set + timeoutSeconds: 60 + failureThreshold: 120 + rdma: + enabled: false + useHostMofed: false + upgradePolicy: + # global switch for automatic upgrade feature + # if set to false all other options are ignored + autoUpgrade: true + # how many nodes can be upgraded in parallel + # 0 means no limit, all nodes will be upgraded in parallel + maxParallelUpgrades: 1 + # maximum number of nodes with the driver installed, that can be unavailable during + # the upgrade. Value can be an absolute number (ex: 5) or + # a percentage of total nodes at the start of upgrade (ex: + # 10%). Absolute number is calculated from percentage by rounding + # up. By default, a fixed value of 25% is used.' + maxUnavailable: 25% + # options for waiting on pod(job) completions + waitForCompletion: + timeoutSeconds: 0 + podSelector: "" + # options for gpu pod deletion + gpuPodDeletion: + force: false + timeoutSeconds: 300 + deleteEmptyDir: false + # options for node drain (`kubectl drain`) before the driver reload + # this is required only if default GPU pod deletions done by the operator + # are not sufficient to re-install the driver + drain: + enable: false + force: false + podSelector: "" + # It's recommended to set a timeout to avoid infinite drain in case non-fatal error keeps happening on retries + timeoutSeconds: 300 + deleteEmptyDir: false + manager: + image: k8s-driver-manager + repository: nvcr.io/nvidia/cloud-native + # When choosing a different version of k8s-driver-manager, DO NOT downgrade to a version lower than v0.6.4 + # to ensure k8s-driver-manager stays compatible with gpu-operator starting from v24.3.0 + version: v0.7.0 + imagePullPolicy: IfNotPresent + env: + - name: ENABLE_GPU_POD_EVICTION + value: "true" + - name: ENABLE_AUTO_DRAIN + value: "false" + - name: DRAIN_USE_FORCE + value: "false" + - name: DRAIN_POD_SELECTOR_LABEL + value: "" + - name: DRAIN_TIMEOUT_SECONDS + value: "0s" + - name: DRAIN_DELETE_EMPTYDIR_DATA + value: "false" + env: [] + resources: {} + # Private mirror repository configuration + repoConfig: + configMapName: "" + # custom ssl key/certificate configuration + certConfig: + name: "" + # vGPU licensing configuration + licensingConfig: + configMapName: "" + nlsEnabled: true + # vGPU topology daemon configuration + virtualTopology: + config: "" + # kernel module configuration for NVIDIA driver + kernelModuleConfig: + name: "" + +toolkit: + enabled: true + repository: nvcr.io/nvidia/k8s + image: container-toolkit + version: v1.17.4-ubuntu20.04 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + resources: {} + installDir: "/usr/local/nvidia" + +devicePlugin: + enabled: true + repository: nvcr.io/nvidia + image: k8s-device-plugin + version: v0.17.0 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + args: [] + env: + - name: PASS_DEVICE_SPECS + value: "true" + - name: FAIL_ON_INIT_ERROR + value: "true" + - name: DEVICE_LIST_STRATEGY + value: envvar + - name: DEVICE_ID_STRATEGY + value: uuid + - name: NVIDIA_VISIBLE_DEVICES + value: all + - name: NVIDIA_DRIVER_CAPABILITIES + value: all + resources: {} + # Plugin configuration + # Use "name" to either point to an existing ConfigMap or to create a new one with a list of configurations(i.e with create=true). + # Use "data" to build an integrated ConfigMap from a set of configurations as + # part of this helm chart. An example of setting "data" might be: + # config: + # name: device-plugin-config + # create: true + # data: + # default: |- + # version: v1 + # flags: + # migStrategy: none + # mig-single: |- + # version: v1 + # flags: + # migStrategy: single + # mig-mixed: |- + # version: v1 + # flags: + # migStrategy: mixed + config: + # Create a ConfigMap (default: false) + create: false + # ConfigMap name (either existing or to create a new one with create=true above) + name: "" + # Default config name within the ConfigMap + default: "" + # Data section for the ConfigMap to create (i.e only applies when create=true) + data: {} + # MPS related configuration for the plugin + mps: + # MPS root path on the host + root: "/run/nvidia/mps" + +# standalone dcgm hostengine +dcgm: + # disabled by default to use embedded nv-hostengine by exporter + enabled: false + repository: nvcr.io/nvidia/cloud-native + image: dcgm + version: 3.3.9-1-ubuntu22.04 + imagePullPolicy: IfNotPresent + args: [] + env: [] + resources: {} + +dcgmExporter: + enabled: true + repository: nvcr.io/nvidia/k8s + image: dcgm-exporter + version: 3.3.9-3.6.1-ubuntu22.04 + imagePullPolicy: IfNotPresent + env: + - name: DCGM_EXPORTER_LISTEN + value: ":9400" + - name: DCGM_EXPORTER_KUBERNETES + value: "true" + - name: DCGM_EXPORTER_COLLECTORS + value: "/etc/dcgm-exporter/dcp-metrics-included.csv" + resources: {} + serviceMonitor: + enabled: false + interval: 15s + honorLabels: false + additionalLabels: {} + relabelings: [] + # - source_labels: + # - __meta_kubernetes_pod_node_name + # regex: (.*) + # target_label: instance + # replacement: $1 + # action: replace + # DCGM Exporter configuration + # This block is used to configure DCGM Exporter to emit a customized list of metrics. + # Use "name" to either point to an existing ConfigMap or to create a new one with a + # list of configurations (i.e with create=true). + # When pointing to an existing ConfigMap, the ConfigMap must exist in the same namespace as the release. + # The metrics are expected to be listed under a key called `dcgm-metrics.csv`. + # Use "data" to build an integrated ConfigMap from a set of custom metrics as + # part of the chart. An example of some custom metrics are shown below. Note that + # the contents of "data" must be in CSV format and be valid DCGM Exporter metric configurations. + # config: + # name: custom-dcgm-exporter-metrics + # create: true + # data: |- + # Format + # If line starts with a '#' it is considered a comment + # DCGM FIELD, Prometheus metric type, help message + + # Clocks + # DCGM_FI_DEV_SM_CLOCK, gauge, SM clock frequency (in MHz). + # DCGM_FI_DEV_MEM_CLOCK, gauge, Memory clock frequency (in MHz). +gfd: + enabled: true + repository: nvcr.io/nvidia + image: k8s-device-plugin + version: v0.17.0 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: + - name: GFD_SLEEP_INTERVAL + value: 60s + - name: GFD_FAIL_ON_INIT_ERROR + value: "true" + resources: {} + +migManager: + enabled: true + repository: nvcr.io/nvidia/cloud-native + image: k8s-mig-manager + version: v0.10.0-ubuntu20.04 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: + - name: WITH_REBOOT + value: "false" + resources: {} + # MIG configuration + # Use "name" to either point to an existing ConfigMap or to create a new one with a list of configurations(i.e with create=true). + # Use "data" to build an integrated ConfigMap from a set of configurations as + # part of this helm chart. An example of setting "data" might be: + # config: + # name: custom-mig-parted-configs + # create: true + # data: |- + # config.yaml: |- + # version: v1 + # mig-configs: + # all-disabled: + # - devices: all + # mig-enabled: false + # custom-mig: + # - devices: [0] + # mig-enabled: false + # - devices: [1] + # mig-enabled: true + # mig-devices: + # "1g.10gb": 7 + # - devices: [2] + # mig-enabled: true + # mig-devices: + # "2g.20gb": 2 + # "3g.40gb": 1 + # - devices: [3] + # mig-enabled: true + # mig-devices: + # "3g.40gb": 1 + # "4g.40gb": 1 + config: + default: "all-disabled" + # Create a ConfigMap (default: false) + create: false + # ConfigMap name (either existing or to create a new one with create=true above) + name: "" + # Data section for the ConfigMap to create (i.e only applies when create=true) + data: {} + gpuClientsConfig: + name: "" + +nodeStatusExporter: + enabled: false + repository: nvcr.io/nvidia/cloud-native + image: gpu-operator-validator + # If version is not specified, then default is to use chart.AppVersion + #version: "" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + resources: {} + +gds: + enabled: false + repository: nvcr.io/nvidia/cloud-native + image: nvidia-fs + version: "2.20.5" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + args: [] + +gdrcopy: + enabled: false + repository: nvcr.io/nvidia/cloud-native + image: gdrdrv + version: "v2.4.1-2" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + args: [] + +vgpuManager: + enabled: false + repository: "" + image: vgpu-manager + version: "" + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + resources: {} + driverManager: + image: k8s-driver-manager + repository: nvcr.io/nvidia/cloud-native + # When choosing a different version of k8s-driver-manager, DO NOT downgrade to a version lower than v0.6.4 + # to ensure k8s-driver-manager stays compatible with gpu-operator starting from v24.3.0 + version: v0.7.0 + imagePullPolicy: IfNotPresent + env: + - name: ENABLE_GPU_POD_EVICTION + value: "false" + - name: ENABLE_AUTO_DRAIN + value: "false" + +vgpuDeviceManager: + enabled: true + repository: nvcr.io/nvidia/cloud-native + image: vgpu-device-manager + version: v0.2.8 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + config: + name: "" + default: "default" + +vfioManager: + enabled: true + repository: nvcr.io/nvidia + image: cuda + version: 12.6.3-base-ubi9 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + resources: {} + driverManager: + image: k8s-driver-manager + repository: nvcr.io/nvidia/cloud-native + # When choosing a different version of k8s-driver-manager, DO NOT downgrade to a version lower than v0.6.4 + # to ensure k8s-driver-manager stays compatible with gpu-operator starting from v24.3.0 + version: v0.7.0 + imagePullPolicy: IfNotPresent + env: + - name: ENABLE_GPU_POD_EVICTION + value: "false" + - name: ENABLE_AUTO_DRAIN + value: "false" + +kataManager: + enabled: false + config: + artifactsDir: "/opt/nvidia-gpu-operator/artifacts/runtimeclasses" + runtimeClasses: + - name: kata-nvidia-gpu + nodeSelector: {} + artifacts: + url: nvcr.io/nvidia/cloud-native/kata-gpu-artifacts:ubuntu22.04-535.54.03 + pullSecret: "" + - name: kata-nvidia-gpu-snp + nodeSelector: + "nvidia.com/cc.capable": "true" + artifacts: + url: nvcr.io/nvidia/cloud-native/kata-gpu-artifacts:ubuntu22.04-535.86.10-snp + pullSecret: "" + repository: nvcr.io/nvidia/cloud-native + image: k8s-kata-manager + version: v0.2.2 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: [] + resources: {} + +sandboxDevicePlugin: + enabled: true + repository: nvcr.io/nvidia + image: kubevirt-gpu-device-plugin + version: v1.2.10 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + args: [] + env: [] + resources: {} + +ccManager: + enabled: false + defaultMode: "off" + repository: nvcr.io/nvidia/cloud-native + image: k8s-cc-manager + version: v0.1.1 + imagePullPolicy: IfNotPresent + imagePullSecrets: [] + env: + - name: CC_CAPABLE_DEVICE_IDS + value: "0x2339,0x2331,0x2330,0x2324,0x2322,0x233d" + resources: {} + +node-feature-discovery: + enableNodeFeatureApi: true + priorityClassName: system-node-critical + gc: + enable: true + replicaCount: 1 + serviceAccount: + name: node-feature-discovery + create: false + worker: + serviceAccount: + name: node-feature-discovery + # disable creation to avoid duplicate serviceaccount creation by master spec below + create: false + tolerations: + - key: "node-role.kubernetes.io/master" + operator: "Equal" + value: "" + effect: "NoSchedule" + - key: "node-role.kubernetes.io/control-plane" + operator: "Equal" + value: "" + effect: "NoSchedule" + - key: nvidia.com/gpu + operator: Exists + effect: NoSchedule + config: + sources: + pci: + deviceClassWhitelist: + - "02" + - "0200" + - "0207" + - "0300" + - "0302" + deviceLabelFields: + - vendor + master: + serviceAccount: + name: node-feature-discovery + create: true + config: + extraLabelNs: ["nvidia.com"] + # noPublish: false + # resourceLabels: ["nvidia.com/feature-1","nvidia.com/feature-2"] + # enableTaints: false + # labelWhiteList: "nvidia.com/gpu" diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.editorconfig b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.editorconfig new file mode 100644 index 000000000..f5ee2f461 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[files/dashboards/*.json] +indent_size = 2 +indent_style = space \ No newline at end of file diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.helmignore b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.helmignore new file mode 100644 index 000000000..9bdbec92b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/.helmignore @@ -0,0 +1,29 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +# helm/charts +OWNERS +hack/ +ci/ +kube-prometheus-*.tgz + +unittests/ +files/dashboards/ diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/CONTRIBUTING.md b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/CONTRIBUTING.md new file mode 100644 index 000000000..f6ce2a323 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/CONTRIBUTING.md @@ -0,0 +1,12 @@ +# Contributing Guidelines + +## How to contribute to this chart + +1. Fork this repository, develop and test your Chart. +1. Bump the chart version for every change. +1. Ensure PR title has the prefix `[kube-prometheus-stack]` +1. When making changes to rules or dashboards, see the README.md section on how to sync data from upstream repositories +1. Check the `hack/minikube` folder has scripts to set up minikube and components of this chart that will allow all components to be scraped. You can use this configuration when validating your changes. +1. Check for changes of RBAC rules. +1. Check for changes in CRD specs. +1. PR must pass the linter (`helm lint`) diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/Chart.yaml new file mode 100644 index 000000000..33cd434a9 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/Chart.yaml @@ -0,0 +1,65 @@ +annotations: + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Chart Source + url: https://github.com/prometheus-community/helm-charts + - name: Upstream Project + url: https://github.com/prometheus-operator/kube-prometheus + artifacthub.io/operator: "true" +apiVersion: v2 +appVersion: v0.74.0 +dependencies: +- condition: crds.enabled + name: crds + repository: "" + version: 0.0.0 +- condition: kubeStateMetrics.enabled + name: kube-state-metrics + repository: https://prometheus-community.github.io/helm-charts + version: 5.20.* +- condition: nodeExporter.enabled + name: prometheus-node-exporter + repository: https://prometheus-community.github.io/helm-charts + version: 4.36.* +- condition: grafana.enabled + name: grafana + repository: https://grafana.github.io/helm-charts + version: 8.2.* +- condition: windowsMonitoring.enabled + name: prometheus-windows-exporter + repository: https://prometheus-community.github.io/helm-charts + version: 0.3.* +description: kube-prometheus-stack collects Kubernetes manifests, Grafana dashboards, + and Prometheus rules combined with documentation and scripts to provide easy to + operate end-to-end Kubernetes cluster monitoring with Prometheus using the Prometheus + Operator. +home: https://github.com/prometheus-operator/kube-prometheus +icon: https://raw.githubusercontent.com/prometheus/prometheus.github.io/master/assets/prometheus_logo-cb55bb5c346.png +keywords: +- operator +- prometheus +- kube-prometheus +kubeVersion: '>=1.19.0-0' +maintainers: +- email: andrew@quadcorps.co.uk + name: andrewgkew +- email: gianrubio@gmail.com + name: gianrubio +- email: github.gkarthiks@gmail.com + name: gkarthiks +- email: kube-prometheus-stack@sisti.pt + name: GMartinez-Sisti +- email: github@jkroepke.de + name: jkroepke +- email: scott@r6by.com + name: scottrigby +- email: miroslav.hadzhiev@gmail.com + name: Xtigyro +- email: quentin.bisson@gmail.com + name: QuentinBisson +name: kube-prometheus-stack +sources: +- https://github.com/prometheus-community/helm-charts +- https://github.com/prometheus-operator/kube-prometheus +type: application +version: 60.5.0 diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/README.md b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/README.md new file mode 100644 index 000000000..cd5ae206c --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/README.md @@ -0,0 +1,1090 @@ +# kube-prometheus-stack + +Installs the [kube-prometheus stack](https://github.com/prometheus-operator/kube-prometheus), a collection of Kubernetes manifests, [Grafana](http://grafana.com/) dashboards, and [Prometheus rules](https://prometheus.io/docs/prometheus/latest/configuration/recording_rules/) combined with documentation and scripts to provide easy to operate end-to-end Kubernetes cluster monitoring with [Prometheus](https://prometheus.io/) using the [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator). + +See the [kube-prometheus](https://github.com/prometheus-operator/kube-prometheus) README for details about components, dashboards, and alerts. + +_Note: This chart was formerly named `prometheus-operator` chart, now renamed to more clearly reflect that it installs the `kube-prometheus` project stack, within which Prometheus Operator is only one component._ + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3+ + +## Get Helm Repository Info + +```console +helm repo add prometheus-community https://prometheus-community.github.io/helm-charts +helm repo update +``` + +_See [`helm repo`](https://helm.sh/docs/helm/helm_repo/) for command documentation._ + +## Install Helm Chart + +```console +helm install [RELEASE_NAME] prometheus-community/kube-prometheus-stack +``` + +_See [configuration](#configuration) below._ + +_See [helm install](https://helm.sh/docs/helm/helm_install/) for command documentation._ + +## Dependencies + +By default this chart installs additional, dependent charts: + +- [prometheus-community/kube-state-metrics](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-state-metrics) +- [prometheus-community/prometheus-node-exporter](https://github.com/prometheus-community/helm-charts/tree/main/charts/prometheus-node-exporter) +- [grafana/grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana) + +To disable dependencies during installation, see [multiple releases](#multiple-releases) below. + +_See [helm dependency](https://helm.sh/docs/helm/helm_dependency/) for command documentation._ + +## Uninstall Helm Chart + +```console +helm uninstall [RELEASE_NAME] +``` + +This removes all the Kubernetes components associated with the chart and deletes the release. + +_See [helm uninstall](https://helm.sh/docs/helm/helm_uninstall/) for command documentation._ + +CRDs created by this chart are not removed by default and should be manually cleaned up: + +```console +kubectl delete crd alertmanagerconfigs.monitoring.coreos.com +kubectl delete crd alertmanagers.monitoring.coreos.com +kubectl delete crd podmonitors.monitoring.coreos.com +kubectl delete crd probes.monitoring.coreos.com +kubectl delete crd prometheusagents.monitoring.coreos.com +kubectl delete crd prometheuses.monitoring.coreos.com +kubectl delete crd prometheusrules.monitoring.coreos.com +kubectl delete crd scrapeconfigs.monitoring.coreos.com +kubectl delete crd servicemonitors.monitoring.coreos.com +kubectl delete crd thanosrulers.monitoring.coreos.com +``` + +## Upgrading Chart + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack +``` + +With Helm v3, CRDs created by this chart are not updated by default and should be manually updated. +Consult also the [Helm Documentation on CRDs](https://helm.sh/docs/chart_best_practices/custom_resource_definitions). + +_See [helm upgrade](https://helm.sh/docs/helm/helm_upgrade/) for command documentation._ + +### Upgrading an existing Release to a new major version + +A major chart version change (like v1.2.3 -> v2.0.0) indicates that there is an incompatible breaking change needing manual actions. + +### From 59.x to 60.x + +This version upgrades the Grafana chart to v8.0.x which introduces Grafana 11. This new major version of Grafana contains some breaking changes described in [Breaking changes in Grafana v11.0](https://grafana.com/docs/grafana/latest/breaking-changes/breaking-changes-v11-0/). + +### From 58.x to 59.x + +This version upgrades Prometheus-Operator to v0.74.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 57.x to 58.x + +This version upgrades Prometheus-Operator to v0.73.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.73.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 56.x to 57.x + +This version upgrades Prometheus-Operator to v0.72.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.72.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 55.x to 56.x + +This version upgrades Prometheus-Operator to v0.71.0, Prometheus to 2.49.1 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.71.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 54.x to 55.x + +This version upgrades Prometheus-Operator to v0.70.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.70.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 53.x to 54.x + +Grafana Helm Chart has bumped to version 7 + +Please note Grafana Helm Chart [changelog](https://github.com/grafana/helm-charts/tree/main/charts/grafana#to-700). + +### From 52.x to 53.x + +This version upgrades Prometheus-Operator to v0.69.1, Prometheus to 2.47.2 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.69.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 51.x to 52.x + +This includes the ability to select between using existing secrets or create new secret objects for various thanos config. The defaults have not changed but if you were setting: + +- `thanosRuler.thanosRulerSpec.alertmanagersConfig` or +- `thanosRuler.thanosRulerSpec.objectStorageConfig` or +- `thanosRuler.thanosRulerSpec.queryConfig` or +- `prometheus.prometheusSpec.thanos.objectStorageConfig` + +you will have to need to set `existingSecret` or `secret` based on your requirement + +For instance, the `thanosRuler.thanosRulerSpec.alertmanagersConfig` used to be configured as follow: + +```yaml +thanosRuler: + thanosRulerSpec: + alertmanagersConfig: + alertmanagers: + - api_version: v2 + http_config: + basic_auth: + username: some_user + password: some_pass + static_configs: + - alertmanager.thanos.io + scheme: http + timeout: 10s +``` + +But it now moved to: + +```yaml +thanosRuler: + thanosRulerSpec: + alertmanagersConfig: + secret: + alertmanagers: + - api_version: v2 + http_config: + basic_auth: + username: some_user + password: some_pass + static_configs: + - alertmanager.thanos.io + scheme: http + timeout: 10s +``` + +or the `thanosRuler.thanosRulerSpec.objectStorageConfig` used to be configured as follow: + +```yaml +thanosRuler: + thanosRulerSpec: + objectStorageConfig: + name: existing-secret-not-created-by-this-chart + key: object-storage-configs.yaml +``` + +But it now moved to: + +```yaml +thanosRuler: + thanosRulerSpec: + objectStorageConfig: + existingSecret: + name: existing-secret-not-created-by-this-chart + key: object-storage-configs.yaml +``` + +### From 50.x to 51.x + +This version upgrades Prometheus-Operator to v0.68.0, Prometheus to 2.47.0 and Thanos to v0.32.2 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.68.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 49.x to 50.x + +This version requires Kubernetes 1.19+. + +We do not expect any breaking changes in this version. + +### From 48.x to 49.x + +This version upgrades Prometheus-Operator to v0.67.1, 0, Alertmanager to v0.26.0, Prometheus to 2.46.0 and Thanos to v0.32.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.67.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 47.x to 48.x + +This version moved all CRDs into a dedicated sub-chart. No new CRDs are introduced in this version. +See [#3548](https://github.com/prometheus-community/helm-charts/issues/3548) for more context. + +We do not expect any breaking changes in this version. + +### From 46.x to 47.x + +This version upgrades Prometheus-Operator to v0.66.0 with new CRDs (PrometheusAgent and ScrapeConfig). + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.66.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 45.x to 46.x + +This version upgrades Prometheus-Operator to v0.65.1 with new CRDs (PrometheusAgent and ScrapeConfig), Prometheus to v2.44.0 and Thanos to v0.31.0. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_scrapeconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.65.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 44.x to 45.x + +This version upgrades Prometheus-Operator to v0.63.0, Prometheus to v2.42.0 and Thanos to v0.30.2. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.63.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 43.x to 44.x + +This version upgrades Prometheus-Operator to v0.62.0, Prometheus to v2.41.0 and Thanos to v0.30.1. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.62.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +If you have explicitly set `prometheusOperator.admissionWebhooks.failurePolicy`, this value is now always used even when `.prometheusOperator.admissionWebhooks.patch.enabled` is `true` (the default). + +The values for `prometheusOperator.image.tag` & `prometheusOperator.prometheusConfigReloader.image.tag` are now empty by default and the Chart.yaml `appVersion` field is used instead. + +### From 42.x to 43.x + +This version upgrades Prometheus-Operator to v0.61.1, Prometheus to v2.40.5 and Thanos to v0.29.0. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.61.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 41.x to 42.x + +This includes the overridability of container registry for all containers at the global level using `global.imageRegistry` or per container image. The defaults have not changed but if you were using a custom image, you will have to override the registry of said custom container image before you upgrade. + +For instance, the prometheus-config-reloader used to be configured as follow: + +```yaml + image: + repository: quay.io/prometheus-operator/prometheus-config-reloader + tag: v0.60.1 + sha: "" +``` + +But it now moved to: + +```yaml + image: + registry: quay.io + repository: prometheus-operator/prometheus-config-reloader + tag: v0.60.1 + sha: "" +``` + +### From 40.x to 41.x + +This version upgrades Prometheus-Operator to v0.60.1, Prometheus to v2.39.1 and Thanos to v0.28.1. +This version also upgrades the Helm charts of kube-state-metrics to 4.20.2, prometheus-node-exporter to 4.3.0 and Grafana to 6.40.4. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.60.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +This version splits kubeScheduler recording and altering rules in separate config values. +Instead of `defaultRules.rules.kubeScheduler` the 2 new variables `defaultRules.rules.kubeSchedulerAlerting` and `defaultRules.rules.kubeSchedulerRecording` are used. + +### From 39.x to 40.x + +This version upgrades Prometheus-Operator to v0.59.1, Prometheus to v2.38.0, kube-state-metrics to v2.6.0 and Thanos to v0.28.0. +This version also upgrades the Helm charts of kube-state-metrics to 4.18.0 and prometheus-node-exporter to 4.2.0. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.59.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +Starting from prometheus-node-exporter version 4.0.0, the `node exporter` chart is using the [Kubernetes recommended labels](https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/). Therefore you have to delete the daemonset before you upgrade. + +```console +kubectl delete daemonset -l app=prometheus-node-exporter +helm upgrade -i kube-prometheus-stack prometheus-community/kube-prometheus-stack +``` + +If you use your own custom [ServiceMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitor) or [PodMonitor](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#podmonitor), please ensure to upgrade their `selector` fields accordingly to the new labels. + +### From 38.x to 39.x + +This upgraded prometheus-operator to v0.58.0 and prometheus to v2.37.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.58.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 37.x to 38.x + +Reverted one of the default metrics relabelings for cAdvisor added in 36.x, due to it breaking container_network_* and various other statistics. If you do not want this change, you will need to override the `kubelet.cAdvisorMetricRelabelings`. + +### From 36.x to 37.x + +This includes some default metric relabelings for cAdvisor and apiserver metrics to reduce cardinality. If you do not want these defaults, you will need to override the `kubeApiServer.metricRelabelings` and or `kubelet.cAdvisorMetricRelabelings`. + +### From 35.x to 36.x + +This upgraded prometheus-operator to v0.57.0 and prometheus to v2.36.1 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.57.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 34.x to 35.x + +This upgraded prometheus-operator to v0.56.0 and prometheus to v2.35.0 + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.56.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 33.x to 34.x + +This upgrades to prometheus-operator to v0.55.0 and prometheus to v2.33.5. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.55.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 32.x to 33.x + +This upgrades the prometheus-node-exporter Chart to v3.0.0. Please review the changes to this subchart if you make customizations to hostMountPropagation. + +### From 31.x to 32.x + +This upgrades to prometheus-operator to v0.54.0 and prometheus to v2.33.1. It also changes the default for `grafana.serviceMonitor.enabled` to `true. + +Run these commands to update the CRDs before applying the upgrade. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.54.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 30.x to 31.x + +This version removes the built-in grafana ServiceMonitor and instead relies on the ServiceMonitor of the sub-chart. +`grafana.serviceMonitor.enabled` must be set instead of `grafana.serviceMonitor.selfMonitor` and the old ServiceMonitor may +need to be manually cleaned up after deploying the new release. + +### From 29.x to 30.x + +This version updates kube-state-metrics to 4.3.0 and uses the new option `kube-state-metrics.releaseLabel=true` which adds the "release" label to kube-state-metrics labels, making scraping of the metrics by kube-prometheus-stack work out of the box again, independent of the used kube-prometheus-stack release name. If you already set the "release" label via `kube-state-metrics.customLabels` you might have to remove that and use it via the new option. + +### From 28.x to 29.x + +This version makes scraping port for kube-controller-manager and kube-scheduler dynamic to reflect changes to default serving ports +for those components in Kubernetes versions v1.22 and v1.23 respectively. + +If you deploy on clusters using version v1.22+, kube-controller-manager will be scraped over HTTPS on port 10257. + +If you deploy on clusters running version v1.23+, kube-scheduler will be scraped over HTTPS on port 10259. + +### From 27.x to 28.x + +This version disables PodSecurityPolicies by default because they are deprecated in Kubernetes 1.21 and will be removed in Kubernetes 1.25. + +If you are using PodSecurityPolicies you can enable the previous behaviour by setting `kube-state-metrics.podSecurityPolicy.enabled`, `prometheus-node-exporter.rbac.pspEnabled`, `grafana.rbac.pspEnabled` and `global.rbac.pspEnabled` to `true`. + +### From 26.x to 27.x + +This version splits prometheus-node-exporter chart recording and altering rules in separate config values. +Instead of `defaultRules.rules.node` the 2 new variables `defaultRules.rules.nodeExporterAlerting` and `defaultRules.rules.nodeExporterRecording` are used. + +Also the following defaultRules.rules has been removed as they had no effect: `kubeApiserverError`, `kubePrometheusNodeAlerting`, `kubernetesAbsent`, `time`. + +The ability to set a rubookUrl via `defaultRules.rules.rubookUrl` was reintroduced. + +### From 25.x to 26.x + +This version enables the prometheus-node-exporter subchart servicemonitor by default again, by setting `prometheus-node-exporter.prometheus.monitor.enabled` to `true`. + +### From 24.x to 25.x + +This version upgrade to prometheus-operator v0.53.1. It removes support for setting a runbookUrl, since the upstream format for runbooks changed. + +```console +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.53.1/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 23.x to 24.x + +The custom `ServiceMonitor` for the _kube-state-metrics_ & _prometheus-node-exporter_ charts have been removed in favour of the built-in sub-chart `ServiceMonitor`; for both sub-charts this means that `ServiceMonitor` customisations happen via the values passed to the chart. If you haven't directly customised this behaviour then there are no changes required to upgrade, but if you have please read the following. + +For _kube-state-metrics_ the `ServiceMonitor` customisation is now set via `kube-state-metrics.prometheus.monitor` and the `kubeStateMetrics.serviceMonitor.selfMonitor.enabled` value has moved to `kube-state-metrics.selfMonitor.enabled`. + +For _prometheus-node-exporter_ the `ServiceMonitor` customisation is now set via `prometheus-node-exporter.prometheus.monitor` and the `nodeExporter.jobLabel` values has moved to `prometheus-node-exporter.prometheus.monitor.jobLabel`. + +### From 22.x to 23.x + +Port names have been renamed for Istio's +[explicit protocol selection](https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/#explicit-protocol-selection). + +| | old value | new value | +|-|-----------|-----------| +| `alertmanager.alertmanagerSpec.portName` | `web` | `http-web` | +| `grafana.service.portName` | `service` | `http-web` | +| `prometheus-node-exporter.service.portName` | `metrics` (hardcoded) | `http-metrics` | +| `prometheus.prometheusSpec.portName` | `web` | `http-web` | + +### From 21.x to 22.x + +Due to the upgrade of the `kube-state-metrics` chart, removal of its deployment/stateful needs to done manually prior to upgrading: + +```console +kubectl delete deployments.apps -l app.kubernetes.io/instance=prometheus-operator,app.kubernetes.io/name=kube-state-metrics --cascade=orphan +``` + +or if you use autosharding: + +```console +kubectl delete statefulsets.apps -l app.kubernetes.io/instance=prometheus-operator,app.kubernetes.io/name=kube-state-metrics --cascade=orphan +``` + +### From 20.x to 21.x + +The config reloader values have been refactored. All the values have been moved to the key `prometheusConfigReloader` and the limits and requests can now be set separately. + +### From 19.x to 20.x + +Version 20 upgrades prometheus-operator from 0.50.x to 0.52.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.52.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 18.x to 19.x + +`kubeStateMetrics.serviceMonitor.namespaceOverride` was removed. +Please use `kube-state-metrics.namespaceOverride` instead. + +### From 17.x to 18.x + +Version 18 upgrades prometheus-operator from 0.49.x to 0.50.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.50.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 16.x to 17.x + +Version 17 upgrades prometheus-operator from 0.48.x to 0.49.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusrules.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.49.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 15.x to 16.x + +Version 16 upgrades kube-state-metrics to v2.0.0. This includes changed command-line arguments and removed metrics, see this [blog post](https://kubernetes.io/blog/2021/04/13/kube-state-metrics-v-2-0/). This version also removes Grafana dashboards that supported Kubernetes 1.14 or earlier. + +### From 14.x to 15.x + +Version 15 upgrades prometheus-operator from 0.46.x to 0.47.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.47.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 13.x to 14.x + +Version 14 upgrades prometheus-operator from 0.45.x to 0.46.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRDs manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_servicemonitors.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.46.0/example/prometheus-operator-crd/monitoring.coreos.com_thanosrulers.yaml +``` + +### From 12.x to 13.x + +Version 13 upgrades prometheus-operator from 0.44.x to 0.45.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.45.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +``` + +### From 11.x to 12.x + +Version 12 upgrades prometheus-operator from 0.43.x to 0.44.x. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.44/example/prometheus-operator-crd/monitoring.coreos.com_prometheuses.yaml +``` + +The chart was migrated to support only helm v3 and later. + +### From 10.x to 11.x + +Version 11 upgrades prometheus-operator from 0.42.x to 0.43.x. Starting with 0.43.x an additional `AlertmanagerConfigs` CRD is introduced. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.43/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +``` + +Version 11 removes the deprecated tlsProxy via ghostunnel in favor of native TLS support the prometheus-operator gained with v0.39.0. + +### From 9.x to 10.x + +Version 10 upgrades prometheus-operator from 0.38.x to 0.42.x. Starting with 0.40.x an additional `Probes` CRD is introduced. Helm does not automatically upgrade or install new CRDs on a chart upgrade, so you have to install the CRD manually before updating: + +```console +kubectl apply -f https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/release-0.42/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +``` + +### From 8.x to 9.x + +Version 9 of the helm chart removes the existing `additionalScrapeConfigsExternal` in favour of `additionalScrapeConfigsSecret`. This change lets users specify the secret name and secret key to use for the additional scrape configuration of prometheus. This is useful for users that have prometheus-operator as a subchart and also have a template that creates the additional scrape configuration. + +### From 7.x to 8.x + +Due to new template functions being used in the rules in version 8.x.x of the chart, an upgrade to Prometheus Operator and Prometheus is necessary in order to support them. First, upgrade to the latest version of 7.x.x + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack --version 7.5.0 +``` + +Then upgrade to 8.x.x + +```console +helm upgrade [RELEASE_NAME] prometheus-community/kube-prometheus-stack --version [8.x.x] +``` + +Minimal recommended Prometheus version for this chart release is `2.12.x` + +### From 6.x to 7.x + +Due to a change in grafana subchart, version 7.x.x now requires Helm >= 2.12.0. + +### From 5.x to 6.x + +Due to a change in deployment labels of kube-state-metrics, the upgrade requires `helm upgrade --force` in order to re-create the deployment. If this is not done an error will occur indicating that the deployment cannot be modified: + +```console +invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{"app.kubernetes.io/name":"kube-state-metrics"}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable +``` + +If this error has already been encountered, a `helm history` command can be used to determine which release has worked, then `helm rollback` to the release, then `helm upgrade --force` to this new one + +## Configuration + +See [Customizing the Chart Before Installing](https://helm.sh/docs/intro/using_helm/#customizing-the-chart-before-installing). To see all configurable options with detailed comments: + +```console +helm show values prometheus-community/kube-prometheus-stack +``` + +You may also `helm show values` on this chart's [dependencies](#dependencies) for additional options. + +### Multiple releases + +The same chart can be used to run multiple Prometheus instances in the same cluster if required. To achieve this, it is necessary to run only one instance of prometheus-operator and a pair of alertmanager pods for an HA configuration, while all other components need to be disabled. To disable a dependency during installation, set `kubeStateMetrics.enabled`, `nodeExporter.enabled` and `grafana.enabled` to `false`. + +## Work-Arounds for Known Issues + +### Running on private GKE clusters + +When Google configure the control plane for private clusters, they automatically configure VPC peering between your Kubernetes cluster’s network and a separate Google managed project. In order to restrict what Google are able to access within your cluster, the firewall rules configured restrict access to your Kubernetes pods. This means that in order to use the webhook component with a GKE private cluster, you must configure an additional firewall rule to allow the GKE control plane access to your webhook pod. + +You can read more information on how to add firewall rules for the GKE control plane nodes in the [GKE docs](https://cloud.google.com/kubernetes-engine/docs/how-to/private-clusters#add_firewall_rules) + +Alternatively, you can disable the hooks by setting `prometheusOperator.admissionWebhooks.enabled=false`. + +## PrometheusRules Admission Webhooks + +With Prometheus Operator version 0.30+, the core Prometheus Operator pod exposes an endpoint that will integrate with the `validatingwebhookconfiguration` Kubernetes feature to prevent malformed rules from being added to the cluster. + +### How the Chart Configures the Hooks + +A validating and mutating webhook configuration requires the endpoint to which the request is sent to use TLS. It is possible to set up custom certificates to do this, but in most cases, a self-signed certificate is enough. The setup of this component requires some more complex orchestration when using helm. The steps are created to be idempotent and to allow turning the feature on and off without running into helm quirks. + +1. A pre-install hook provisions a certificate into the same namespace using a format compatible with provisioning using end user certificates. If the certificate already exists, the hook exits. +2. The prometheus operator pod is configured to use a TLS proxy container, which will load that certificate. +3. Validating and Mutating webhook configurations are created in the cluster, with their failure mode set to Ignore. This allows rules to be created by the same chart at the same time, even though the webhook has not yet been fully set up - it does not have the correct CA field set. +4. A post-install hook reads the CA from the secret created by step 1 and patches the Validating and Mutating webhook configurations. This process will allow a custom CA provisioned by some other process to also be patched into the webhook configurations. The chosen failure policy is also patched into the webhook configurations + +### Alternatives + +It should be possible to use [jetstack/cert-manager](https://github.com/jetstack/cert-manager) if a more complete solution is required, but it has not been tested. + +You can enable automatic self-signed TLS certificate provisioning via cert-manager by setting the `prometheusOperator.admissionWebhooks.certManager.enabled` value to true. + +### Limitations + +Because the operator can only run as a single pod, there is potential for this component failure to cause rule deployment failure. Because this risk is outweighed by the benefit of having validation, the feature is enabled by default. + +## Developing Prometheus Rules and Grafana Dashboards + +This chart Grafana Dashboards and Prometheus Rules are just a copy from [prometheus-operator/prometheus-operator](https://github.com/prometheus-operator/prometheus-operator) and other sources, synced (with alterations) by scripts in [hack](hack) folder. In order to introduce any changes you need to first [add them to the original repository](https://github.com/prometheus-operator/kube-prometheus/blob/main/docs/customizations/developing-prometheus-rules-and-grafana-dashboards.md) and then sync there by scripts. + +## Further Information + +For more in-depth documentation of configuration options meanings, please see + +- [Prometheus Operator](https://github.com/prometheus-operator/prometheus-operator) +- [Prometheus](https://prometheus.io/docs/introduction/overview/) +- [Grafana](https://github.com/grafana/helm-charts/tree/main/charts/grafana#grafana-helm-chart) + +## prometheus.io/scrape + +The prometheus operator does not support annotation-based discovery of services, using the `PodMonitor` or `ServiceMonitor` CRD in its place as they provide far more configuration options. +For information on how to use PodMonitors/ServiceMonitors, please see the documentation on the `prometheus-operator/prometheus-operator` documentation here: + +- [ServiceMonitors](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#include-servicemonitors) +- [PodMonitors](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/getting-started.md#include-podmonitors) +- [Running Exporters](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/user-guides/running-exporters.md) + +By default, Prometheus discovers PodMonitors and ServiceMonitors within its namespace, that are labeled with the same release tag as the prometheus-operator release. +Sometimes, you may need to discover custom PodMonitors/ServiceMonitors, for example used to scrape data from third-party applications. +An easy way of doing this, without compromising the default PodMonitors/ServiceMonitors discovery, is allowing Prometheus to discover all PodMonitors/ServiceMonitors within its namespace, without applying label filtering. +To do so, you can set `prometheus.prometheusSpec.podMonitorSelectorNilUsesHelmValues` and `prometheus.prometheusSpec.serviceMonitorSelectorNilUsesHelmValues` to `false`. + +## Migrating from stable/prometheus-operator chart + +## Zero downtime + +Since `kube-prometheus-stack` is fully compatible with the `stable/prometheus-operator` chart, a migration without downtime can be achieved. +However, the old name prefix needs to be kept. If you want the new name please follow the step by step guide below (with downtime). + +You can override the name to achieve this: + +```console +helm upgrade prometheus-operator prometheus-community/kube-prometheus-stack -n monitoring --reuse-values --set nameOverride=prometheus-operator +``` + +**Note**: It is recommended to run this first with `--dry-run --debug`. + +## Redeploy with new name (downtime) + +If the **prometheus-operator** values are compatible with the new **kube-prometheus-stack** chart, please follow the below steps for migration: + +> The guide presumes that chart is deployed in `monitoring` namespace and the deployments are running there. If in other namespace, please replace the `monitoring` to the deployed namespace. + +1. Patch the PersistenceVolume created/used by the prometheus-operator chart to `Retain` claim policy: + + ```console + kubectl patch pv/ -p '{"spec":{"persistentVolumeReclaimPolicy":"Retain"}}' + ``` + + **Note:** To execute the above command, the user must have a cluster wide permission. Please refer [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) + +2. Uninstall the **prometheus-operator** release and delete the existing PersistentVolumeClaim, and verify PV become Released. + + ```console + helm uninstall prometheus-operator -n monitoring + kubectl delete pvc/ -n monitoring + ``` + + Additionally, you have to manually remove the remaining `prometheus-operator-kubelet` service. + + ```console + kubectl delete service/prometheus-operator-kubelet -n kube-system + ``` + + You can choose to remove all your existing CRDs (ServiceMonitors, Podmonitors, etc.) if you want to. + +3. Remove current `spec.claimRef` values to change the PV's status from Released to Available. + + ```console + kubectl patch pv/ --type json -p='[{"op": "remove", "path": "/spec/claimRef"}]' -n monitoring + ``` + +**Note:** To execute the above command, the user must have a cluster wide permission. Please refer to [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac/) + +After these steps, proceed to a fresh **kube-prometheus-stack** installation and make sure the current release of **kube-prometheus-stack** matching the `volumeClaimTemplate` values in the `values.yaml`. + +The binding is done via matching a specific amount of storage requested and with certain access modes. + +For example, if you had storage specified as this with **prometheus-operator**: + +```yaml +volumeClaimTemplate: + spec: + storageClassName: gp2 + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 50Gi +``` + +You have to specify matching `volumeClaimTemplate` with 50Gi storage and `ReadWriteOnce` access mode. + +Additionally, you should check the current AZ of your legacy installation's PV, and configure the fresh release to use the same AZ as the old one. If the pods are in a different AZ than the PV, the release will fail to bind the existing one, hence creating a new PV. + +This can be achieved either by specifying the labels through `values.yaml`, e.g. setting `prometheus.prometheusSpec.nodeSelector` to: + +```yaml +nodeSelector: + failure-domain.beta.kubernetes.io/zone: east-west-1a +``` + +or passing these values as `--set` overrides during installation. + +The new release should now re-attach your previously released PV with its content. + +## Migrating from coreos/prometheus-operator chart + +The multiple charts have been combined into a single chart that installs prometheus operator, prometheus, alertmanager, grafana as well as the multitude of exporters necessary to monitor a cluster. + +There is no simple and direct migration path between the charts as the changes are extensive and intended to make the chart easier to support. + +The capabilities of the old chart are all available in the new chart, including the ability to run multiple prometheus instances on a single cluster - you will need to disable the parts of the chart you do not wish to deploy. + +You can check out the tickets for this change [here](https://github.com/prometheus-operator/prometheus-operator/issues/592) and [here](https://github.com/helm/charts/pull/6765). + +### High-level overview of Changes + +#### Added dependencies + +The chart has added 3 [dependencies](#dependencies). + +- Node-Exporter, Kube-State-Metrics: These components are loaded as dependencies into the chart, and are relatively simple components +- Grafana: The Grafana chart is more feature-rich than this chart - it contains a sidecar that is able to load data sources and dashboards from configmaps deployed into the same cluster. For more information check out the [documentation for the chart](https://github.com/grafana/helm-charts/blob/main/charts/grafana/README.md) + +#### Kubelet Service + +Because the kubelet service has a new name in the chart, make sure to clean up the old kubelet service in the `kube-system` namespace to prevent counting container metrics twice. + +#### Persistent Volumes + +If you would like to keep the data of the current persistent volumes, it should be possible to attach existing volumes to new PVCs and PVs that are created using the conventions in the new chart. For example, in order to use an existing Azure disk for a helm release called `prometheus-migration` the following resources can be created: + +```yaml +apiVersion: v1 +kind: PersistentVolume +metadata: + name: pvc-prometheus-migration-prometheus-0 +spec: + accessModes: + - ReadWriteOnce + azureDisk: + cachingMode: None + diskName: pvc-prometheus-migration-prometheus-0 + diskURI: /subscriptions/f5125d82-2622-4c50-8d25-3f7ba3e9ac4b/resourceGroups/sample-migration-resource-group/providers/Microsoft.Compute/disks/pvc-prometheus-migration-prometheus-0 + fsType: "" + kind: Managed + readOnly: false + capacity: + storage: 1Gi + persistentVolumeReclaimPolicy: Delete + storageClassName: prometheus + volumeMode: Filesystem +``` + +```yaml +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + labels: + app.kubernetes.io/name: prometheus + prometheus: prometheus-migration-prometheus + name: prometheus-prometheus-migration-prometheus-db-prometheus-prometheus-migration-prometheus-0 + namespace: monitoring +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + storageClassName: prometheus + volumeMode: Filesystem + volumeName: pvc-prometheus-migration-prometheus-0 +``` + +The PVC will take ownership of the PV and when you create a release using a persistent volume claim template it will use the existing PVCs as they match the naming convention used by the chart. For other cloud providers similar approaches can be used. + +#### KubeProxy + +The metrics bind address of kube-proxy is default to `127.0.0.1:10249` that prometheus instances **cannot** access to. You should expose metrics by changing `metricsBindAddress` field value to `0.0.0.0:10249` if you want to collect them. + +Depending on the cluster, the relevant part `config.conf` will be in ConfigMap `kube-system/kube-proxy` or `kube-system/kube-proxy-config`. For example: + +```console +kubectl -n kube-system edit cm kube-proxy +``` + +```yaml +apiVersion: v1 +data: + config.conf: |- + apiVersion: kubeproxy.config.k8s.io/v1alpha1 + kind: KubeProxyConfiguration + # ... + # metricsBindAddress: 127.0.0.1:10249 + metricsBindAddress: 0.0.0.0:10249 + # ... + kubeconfig.conf: |- + # ... +kind: ConfigMap +metadata: + labels: + app: kube-proxy + name: kube-proxy + namespace: kube-system +``` diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/Chart.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/Chart.yaml new file mode 100644 index 000000000..adb9e4a5d --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +name: crds +version: 0.0.0 diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/README.md b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/README.md new file mode 100644 index 000000000..02092b964 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/README.md @@ -0,0 +1,3 @@ +# crds subchart + +See: [https://github.com/prometheus-community/helm-charts/issues/3548](https://github.com/prometheus-community/helm-charts/issues/3548) diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagerconfigs.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagerconfigs.yaml new file mode 100644 index 000000000..e8c9fbcd0 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagerconfigs.yaml @@ -0,0 +1,5866 @@ +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagerconfigs.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + operator.prometheus.io/version: 0.74.0 + name: alertmanagerconfigs.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: AlertmanagerConfig + listKind: AlertmanagerConfigList + plural: alertmanagerconfigs + shortNames: + - amcfg + singular: alertmanagerconfig + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: |- + AlertmanagerConfig configures the Prometheus Alertmanager, + specifying how alerts should be grouped, inhibited and notified to external systems. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + AlertmanagerConfigSpec is a specification of the desired behavior of the Alertmanager configuration. + By definition, the Alertmanager configuration only applies to alerts for which + the `namespace` label is equal to the namespace of the AlertmanagerConfig resource. + properties: + inhibitRules: + description: |- + List of inhibition rules. The rules will only apply to alerts matching + the resource's namespace. + items: + description: |- + InhibitRule defines an inhibition rule that allows to mute alerts when other + alerts are already firing. + See https://prometheus.io/docs/alerting/latest/configuration/#inhibit_rule + properties: + equal: + description: |- + Labels that must have an equal value in the source and target alert for + the inhibition to take effect. + items: + type: string + type: array + sourceMatch: + description: |- + Matchers for which one or more alerts have to exist for the inhibition + to take effect. The operator enforces that the alert matches the + resource's namespace. + items: + description: Matcher defines how to match on alert's labels. + properties: + matchType: + description: |- + Match operation available with AlertManager >= v0.22.0 and + takes precedence over Regex (deprecated) if non-empty. + enum: + - '!=' + - = + - =~ + - '!~' + type: string + name: + description: Label to match. + minLength: 1 + type: string + regex: + description: |- + Whether to match on equality (false) or regular-expression (true). + Deprecated: for AlertManager >= v0.22.0, `matchType` should be used instead. + type: boolean + value: + description: Label value to match. + type: string + required: + - name + type: object + type: array + targetMatch: + description: |- + Matchers that have to be fulfilled in the alerts to be muted. The + operator enforces that the alert matches the resource's namespace. + items: + description: Matcher defines how to match on alert's labels. + properties: + matchType: + description: |- + Match operation available with AlertManager >= v0.22.0 and + takes precedence over Regex (deprecated) if non-empty. + enum: + - '!=' + - = + - =~ + - '!~' + type: string + name: + description: Label to match. + minLength: 1 + type: string + regex: + description: |- + Whether to match on equality (false) or regular-expression (true). + Deprecated: for AlertManager >= v0.22.0, `matchType` should be used instead. + type: boolean + value: + description: Label value to match. + type: string + required: + - name + type: object + type: array + type: object + type: array + muteTimeIntervals: + description: List of MuteTimeInterval specifying when the routes should + be muted. + items: + description: MuteTimeInterval specifies the periods in time when + notifications will be muted + properties: + name: + description: Name of the time interval + type: string + timeIntervals: + description: TimeIntervals is a list of TimeInterval + items: + description: TimeInterval describes intervals of time + properties: + daysOfMonth: + description: DaysOfMonth is a list of DayOfMonthRange + items: + description: DayOfMonthRange is an inclusive range of + days of the month beginning at 1 + properties: + end: + description: End of the inclusive range + maximum: 31 + minimum: -31 + type: integer + start: + description: Start of the inclusive range + maximum: 31 + minimum: -31 + type: integer + type: object + type: array + months: + description: Months is a list of MonthRange + items: + description: |- + MonthRange is an inclusive range of months of the year beginning in January + Months can be specified by name (e.g 'January') by numerical month (e.g '1') or as an inclusive range (e.g 'January:March', '1:3', '1:March') + pattern: ^((?i)january|february|march|april|may|june|july|august|september|october|november|december|1[0-2]|[1-9])(?:((:((?i)january|february|march|april|may|june|july|august|september|october|november|december|1[0-2]|[1-9]))$)|$) + type: string + type: array + times: + description: Times is a list of TimeRange + items: + description: TimeRange defines a start and end time + in 24hr format + properties: + endTime: + description: EndTime is the end time in 24hr format. + pattern: ^((([01][0-9])|(2[0-3])):[0-5][0-9])$|(^24:00$) + type: string + startTime: + description: StartTime is the start time in 24hr + format. + pattern: ^((([01][0-9])|(2[0-3])):[0-5][0-9])$|(^24:00$) + type: string + type: object + type: array + weekdays: + description: Weekdays is a list of WeekdayRange + items: + description: |- + WeekdayRange is an inclusive range of days of the week beginning on Sunday + Days can be specified by name (e.g 'Sunday') or as an inclusive range (e.g 'Monday:Friday') + pattern: ^((?i)sun|mon|tues|wednes|thurs|fri|satur)day(?:((:(sun|mon|tues|wednes|thurs|fri|satur)day)$)|$) + type: string + type: array + years: + description: Years is a list of YearRange + items: + description: YearRange is an inclusive range of years + pattern: ^2\d{3}(?::2\d{3}|$) + type: string + type: array + type: object + type: array + type: object + type: array + receivers: + description: List of receivers. + items: + description: Receiver defines one or more notification integrations. + properties: + discordConfigs: + description: List of Discord configurations. + items: + description: |- + DiscordConfig configures notifications via Discord. + See https://prometheus.io/docs/alerting/latest/configuration/#discord_config + properties: + apiURL: + description: |- + The secret's key that contains the Discord webhook URL. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: The template of the message's body. + type: string + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + title: + description: The template of the message's title. + type: string + required: + - apiURL + type: object + type: array + emailConfigs: + description: List of Email configurations. + items: + description: EmailConfig configures notifications via Email. + properties: + authIdentity: + description: The identity to use for authentication. + type: string + authPassword: + description: |- + The secret's key that contains the password to use for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + authSecret: + description: |- + The secret's key that contains the CRAM-MD5 secret. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + authUsername: + description: The username to use for authentication. + type: string + from: + description: The sender address. + type: string + headers: + description: |- + Further headers email header key/value pairs. Overrides any headers + previously set by the notification implementation. + items: + description: KeyValue defines a (key, value) tuple. + properties: + key: + description: Key of the tuple. + minLength: 1 + type: string + value: + description: Value of the tuple. + type: string + required: + - key + - value + type: object + type: array + hello: + description: The hostname to identify to the SMTP server. + type: string + html: + description: The HTML body of the email notification. + type: string + requireTLS: + description: |- + The SMTP TLS requirement. + Note that Go does not support unencrypted connections to remote SMTP endpoints. + type: boolean + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + smarthost: + description: The SMTP host and port through which emails + are sent. E.g. example.com:25 + type: string + text: + description: The text body of the email notification. + type: string + tlsConfig: + description: TLS configuration + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to use + for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for + the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when doing + client-authentication. + properties: + configMap: + description: ConfigMap containing data to use + for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for + the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key file + for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the targets. + type: string + type: object + to: + description: The email address to send notifications to. + type: string + type: object + type: array + msteamsConfigs: + description: |- + List of MSTeams configurations. + It requires Alertmanager >= 0.26.0. + items: + description: |- + MSTeamsConfig configures notifications via Microsoft Teams. + It requires Alertmanager >= 0.26.0. + properties: + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + sendResolved: + description: Whether to notify about resolved alerts. + type: boolean + summary: + description: |- + Message summary template. + It requires Alertmanager >= 0.27.0. + type: string + text: + description: Message body template. + type: string + title: + description: Message title template. + type: string + webhookUrl: + description: MSTeams webhook URL. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + required: + - webhookUrl + type: object + type: array + name: + description: Name of the receiver. Must be unique across all + items from the list. + minLength: 1 + type: string + opsgenieConfigs: + description: List of OpsGenie configurations. + items: + description: |- + OpsGenieConfig configures notifications via OpsGenie. + See https://prometheus.io/docs/alerting/latest/configuration/#opsgenie_config + properties: + actions: + description: Comma separated list of actions that will + be available for the alert. + type: string + apiKey: + description: |- + The secret's key that contains the OpsGenie API key. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + apiURL: + description: The URL to send OpsGenie API requests to. + type: string + description: + description: Description of the incident. + type: string + details: + description: A set of arbitrary key/value pairs that provide + further detail about the incident. + items: + description: KeyValue defines a (key, value) tuple. + properties: + key: + description: Key of the tuple. + minLength: 1 + type: string + value: + description: Value of the tuple. + type: string + required: + - key + - value + type: object + type: array + entity: + description: Optional field that can be used to specify + which domain alert is related to. + type: string + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: Alert text limited to 130 characters. + type: string + note: + description: Additional alert note. + type: string + priority: + description: Priority level of alert. Possible values + are P1, P2, P3, P4, and P5. + type: string + responders: + description: List of responders responsible for notifications. + items: + description: |- + OpsGenieConfigResponder defines a responder to an incident. + One of `id`, `name` or `username` has to be defined. + properties: + id: + description: ID of the responder. + type: string + name: + description: Name of the responder. + type: string + type: + description: Type of responder. + minLength: 1 + type: string + username: + description: Username of the responder. + type: string + required: + - type + type: object + type: array + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + source: + description: Backlink to the sender of the notification. + type: string + tags: + description: Comma separated list of tags attached to + the notifications. + type: string + updateAlerts: + description: |- + Whether to update message and description of the alert in OpsGenie if it already exists + By default, the alert is never updated in OpsGenie, the new message only appears in activity log. + type: boolean + type: object + type: array + pagerdutyConfigs: + description: List of PagerDuty configurations. + items: + description: |- + PagerDutyConfig configures notifications via PagerDuty. + See https://prometheus.io/docs/alerting/latest/configuration/#pagerduty_config + properties: + class: + description: The class/type of the event. + type: string + client: + description: Client identification. + type: string + clientURL: + description: Backlink to the sender of notification. + type: string + component: + description: The part or component of the affected system + that is broken. + type: string + description: + description: Description of the incident. + type: string + details: + description: Arbitrary key/value pairs that provide further + detail about the incident. + items: + description: KeyValue defines a (key, value) tuple. + properties: + key: + description: Key of the tuple. + minLength: 1 + type: string + value: + description: Value of the tuple. + type: string + required: + - key + - value + type: object + type: array + group: + description: A cluster or grouping of sources. + type: string + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + pagerDutyImageConfigs: + description: A list of image details to attach that provide + further detail about an incident. + items: + description: PagerDutyImageConfig attaches images to + an incident + properties: + alt: + description: Alt is the optional alternative text + for the image. + type: string + href: + description: Optional URL; makes the image a clickable + link. + type: string + src: + description: Src of the image being attached to + the incident + type: string + type: object + type: array + pagerDutyLinkConfigs: + description: A list of link details to attach that provide + further detail about an incident. + items: + description: PagerDutyLinkConfig attaches text links + to an incident + properties: + alt: + description: Text that describes the purpose of + the link, and can be used as the link's text. + type: string + href: + description: Href is the URL of the link to be attached + type: string + type: object + type: array + routingKey: + description: |- + The secret's key that contains the PagerDuty integration key (when using + Events API v2). Either this field or `serviceKey` needs to be defined. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + serviceKey: + description: |- + The secret's key that contains the PagerDuty service key (when using + integration type "Prometheus"). Either this field or `routingKey` needs to + be defined. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + severity: + description: Severity of the incident. + type: string + url: + description: The URL to send requests to. + type: string + type: object + type: array + pushoverConfigs: + description: List of Pushover configurations. + items: + description: |- + PushoverConfig configures notifications via Pushover. + See https://prometheus.io/docs/alerting/latest/configuration/#pushover_config + properties: + device: + description: The name of a device to send the notification + to + type: string + expire: + description: |- + How long your notification will continue to be retried for, unless the user + acknowledges the notification. + pattern: ^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$ + type: string + html: + description: Whether notification message is HTML or plain + text. + type: boolean + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: Notification message. + type: string + priority: + description: Priority, see https://pushover.net/api#priority + type: string + retry: + description: |- + How often the Pushover servers will send the same notification to the user. + Must be at least 30 seconds. + pattern: ^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$ + type: string + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + sound: + description: The name of one of the sounds supported by + device clients to override the user's default sound + choice + type: string + title: + description: Notification title. + type: string + token: + description: |- + The secret's key that contains the registered application's API token, see https://pushover.net/apps. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + Either `token` or `tokenFile` is required. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + tokenFile: + description: |- + The token file that contains the registered application's API token, see https://pushover.net/apps. + Either `token` or `tokenFile` is required. + It requires Alertmanager >= v0.26.0. + type: string + url: + description: A supplementary URL shown alongside the message. + type: string + urlTitle: + description: A title for supplementary URL, otherwise + just the URL is shown + type: string + userKey: + description: |- + The secret's key that contains the recipient user's user key. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + Either `userKey` or `userKeyFile` is required. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + userKeyFile: + description: |- + The user key file that contains the recipient user's user key. + Either `userKey` or `userKeyFile` is required. + It requires Alertmanager >= v0.26.0. + type: string + type: object + type: array + slackConfigs: + description: List of Slack configurations. + items: + description: |- + SlackConfig configures notifications via Slack. + See https://prometheus.io/docs/alerting/latest/configuration/#slack_config + properties: + actions: + description: A list of Slack actions that are sent with + each notification. + items: + description: |- + SlackAction configures a single Slack action that is sent with each + notification. + See https://api.slack.com/docs/message-attachments#action_fields and + https://api.slack.com/docs/message-buttons for more information. + properties: + confirm: + description: |- + SlackConfirmationField protect users from destructive actions or + particularly distinguished decisions by asking them to confirm their button + click one more time. + See https://api.slack.com/docs/interactive-message-field-guide#confirmation_fields + for more information. + properties: + dismissText: + type: string + okText: + type: string + text: + minLength: 1 + type: string + title: + type: string + required: + - text + type: object + name: + type: string + style: + type: string + text: + minLength: 1 + type: string + type: + minLength: 1 + type: string + url: + type: string + value: + type: string + required: + - text + - type + type: object + type: array + apiURL: + description: |- + The secret's key that contains the Slack webhook URL. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + callbackId: + type: string + channel: + description: The channel or user to send notifications + to. + type: string + color: + type: string + fallback: + type: string + fields: + description: A list of Slack fields that are sent with + each notification. + items: + description: |- + SlackField configures a single Slack field that is sent with each notification. + Each field must contain a title, value, and optionally, a boolean value to indicate if the field + is short enough to be displayed next to other fields designated as short. + See https://api.slack.com/docs/message-attachments#fields for more information. + properties: + short: + type: boolean + title: + minLength: 1 + type: string + value: + minLength: 1 + type: string + required: + - title + - value + type: object + type: array + footer: + type: string + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + iconEmoji: + type: string + iconURL: + type: string + imageURL: + type: string + linkNames: + type: boolean + mrkdwnIn: + items: + type: string + type: array + pretext: + type: string + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + shortFields: + type: boolean + text: + type: string + thumbURL: + type: string + title: + type: string + titleLink: + type: string + username: + type: string + type: object + type: array + snsConfigs: + description: List of SNS configurations + items: + description: |- + SNSConfig configures notifications via AWS SNS. + See https://prometheus.io/docs/alerting/latest/configuration/#sns_configs + properties: + apiURL: + description: |- + The SNS API URL i.e. https://sns.us-east-2.amazonaws.com. + If not specified, the SNS API URL from the SNS SDK will be used. + type: string + attributes: + additionalProperties: + type: string + description: SNS message attributes. + type: object + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: The message content of the SNS notification. + type: string + phoneNumber: + description: |- + Phone number if message is delivered via SMS in E.164 format. + If you don't specify this value, you must specify a value for the TopicARN or TargetARN. + type: string + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + sigv4: + description: Configures AWS's Signature Verification 4 + signing process to sign requests. + properties: + accessKey: + description: |- + AccessKey is the AWS API key. If not specified, the environment variable + `AWS_ACCESS_KEY_ID` is used. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + profile: + description: Profile is the named AWS profile used + to authenticate. + type: string + region: + description: Region is the AWS region. If blank, the + region from the default credentials chain used. + type: string + roleArn: + description: RoleArn is the named AWS profile used + to authenticate. + type: string + secretKey: + description: |- + SecretKey is the AWS API secret. If not specified, the environment + variable `AWS_SECRET_ACCESS_KEY` is used. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + subject: + description: Subject line when the message is delivered + to email endpoints. + type: string + targetARN: + description: |- + The mobile platform endpoint ARN if message is delivered via mobile notifications. + If you don't specify this value, you must specify a value for the topic_arn or PhoneNumber. + type: string + topicARN: + description: |- + SNS topic ARN, i.e. arn:aws:sns:us-east-2:698519295917:My-Topic + If you don't specify this value, you must specify a value for the PhoneNumber or TargetARN. + type: string + type: object + type: array + telegramConfigs: + description: List of Telegram configurations. + items: + description: |- + TelegramConfig configures notifications via Telegram. + See https://prometheus.io/docs/alerting/latest/configuration/#telegram_config + properties: + apiURL: + description: |- + The Telegram API URL i.e. https://api.telegram.org. + If not specified, default API URL will be used. + type: string + botToken: + description: |- + Telegram bot token. It is mutually exclusive with `botTokenFile`. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + + + Either `botToken` or `botTokenFile` is required. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + botTokenFile: + description: |- + File to read the Telegram bot token from. It is mutually exclusive with `botToken`. + Either `botToken` or `botTokenFile` is required. + + + It requires Alertmanager >= v0.26.0. + type: string + chatID: + description: The Telegram chat ID. + format: int64 + type: integer + disableNotifications: + description: Disable telegram notifications + type: boolean + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: Message template + type: string + parseMode: + description: Parse mode for telegram message + enum: + - MarkdownV2 + - Markdown + - HTML + type: string + sendResolved: + description: Whether to notify about resolved alerts. + type: boolean + type: object + type: array + victoropsConfigs: + description: List of VictorOps configurations. + items: + description: |- + VictorOpsConfig configures notifications via VictorOps. + See https://prometheus.io/docs/alerting/latest/configuration/#victorops_config + properties: + apiKey: + description: |- + The secret's key that contains the API key to use when talking to the VictorOps API. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + apiUrl: + description: The VictorOps API URL. + type: string + customFields: + description: Additional custom fields for notification. + items: + description: KeyValue defines a (key, value) tuple. + properties: + key: + description: Key of the tuple. + minLength: 1 + type: string + value: + description: Value of the tuple. + type: string + required: + - key + - value + type: object + type: array + entityDisplayName: + description: Contains summary of the alerted problem. + type: string + httpConfig: + description: The HTTP client's configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + messageType: + description: Describes the behavior of the alert (CRITICAL, + WARNING, INFO). + type: string + monitoringTool: + description: The monitoring tool the state message is + from. + type: string + routingKey: + description: A key used to map the alert to a team. + type: string + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + stateMessage: + description: Contains long explanation of the alerted + problem. + type: string + type: object + type: array + webexConfigs: + description: List of Webex configurations. + items: + description: |- + WebexConfig configures notification via Cisco Webex + See https://prometheus.io/docs/alerting/latest/configuration/#webex_config + properties: + apiURL: + description: |- + The Webex Teams API URL i.e. https://webexapis.com/v1/messages + Provide if different from the default API URL. + pattern: ^https?://.+$ + type: string + httpConfig: + description: |- + The HTTP client's configuration. + You must supply the bot token via the `httpConfig.authorization` field. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: Message template + type: string + roomID: + description: ID of the Webex Teams room where to send + the messages. + minLength: 1 + type: string + sendResolved: + description: Whether to notify about resolved alerts. + type: boolean + required: + - roomID + type: object + type: array + webhookConfigs: + description: List of webhook configurations. + items: + description: |- + WebhookConfig configures notifications via a generic receiver supporting the webhook payload. + See https://prometheus.io/docs/alerting/latest/configuration/#webhook_config + properties: + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + maxAlerts: + description: Maximum number of alerts to be sent per webhook + message. When 0, all alerts are included. + format: int32 + minimum: 0 + type: integer + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + url: + description: |- + The URL to send HTTP POST requests to. `urlSecret` takes precedence over + `url`. One of `urlSecret` and `url` should be defined. + type: string + urlSecret: + description: |- + The secret's key that contains the webhook URL to send HTTP requests to. + `urlSecret` takes precedence over `url`. One of `urlSecret` and `url` + should be defined. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + type: array + wechatConfigs: + description: List of WeChat configurations. + items: + description: |- + WeChatConfig configures notifications via WeChat. + See https://prometheus.io/docs/alerting/latest/configuration/#wechat_config + properties: + agentID: + type: string + apiSecret: + description: |- + The secret's key that contains the WeChat API key. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + apiURL: + description: The WeChat API URL. + type: string + corpID: + description: The corp id for authentication. + type: string + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the + namespace that contains the credentials for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the AlertmanagerConfig + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the + client should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch + a token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes + used for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to + fetch the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when + doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to + use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use + for the targets. + properties: + key: + description: The key of the secret to + select from. Must be a valid secret + key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key + file for the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the + targets. + type: string + type: object + type: object + message: + description: API request data as defined by the WeChat + API. + type: string + messageType: + type: string + sendResolved: + description: Whether or not to notify about resolved alerts. + type: boolean + toParty: + type: string + toTag: + type: string + toUser: + type: string + type: object + type: array + required: + - name + type: object + type: array + route: + description: |- + The Alertmanager route definition for alerts matching the resource's + namespace. If present, it will be added to the generated Alertmanager + configuration as a first-level route. + properties: + activeTimeIntervals: + description: ActiveTimeIntervals is a list of MuteTimeInterval + names when this route should be active. + items: + type: string + type: array + continue: + description: |- + Boolean indicating whether an alert should continue matching subsequent + sibling nodes. It will always be overridden to true for the first-level + route by the Prometheus operator. + type: boolean + groupBy: + description: |- + List of labels to group by. + Labels must not be repeated (unique list). + Special label "..." (aggregate by all possible labels), if provided, must be the only element in the list. + items: + type: string + type: array + groupInterval: + description: |- + How long to wait before sending an updated notification. + Must match the regular expression`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$` + Example: "5m" + type: string + groupWait: + description: |- + How long to wait before sending the initial notification. + Must match the regular expression`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$` + Example: "30s" + type: string + matchers: + description: |- + List of matchers that the alert's labels should match. For the first + level route, the operator removes any existing equality and regexp + matcher on the `namespace` label and adds a `namespace: ` matcher. + items: + description: Matcher defines how to match on alert's labels. + properties: + matchType: + description: |- + Match operation available with AlertManager >= v0.22.0 and + takes precedence over Regex (deprecated) if non-empty. + enum: + - '!=' + - = + - =~ + - '!~' + type: string + name: + description: Label to match. + minLength: 1 + type: string + regex: + description: |- + Whether to match on equality (false) or regular-expression (true). + Deprecated: for AlertManager >= v0.22.0, `matchType` should be used instead. + type: boolean + value: + description: Label value to match. + type: string + required: + - name + type: object + type: array + muteTimeIntervals: + description: |- + Note: this comment applies to the field definition above but appears + below otherwise it gets included in the generated manifest. + CRD schema doesn't support self-referential types for now (see + https://github.com/kubernetes/kubernetes/issues/62872). We have to use + an alternative type to circumvent the limitation. The downside is that + the Kube API can't validate the data beyond the fact that it is a valid + JSON representation. + MuteTimeIntervals is a list of MuteTimeInterval names that will mute this route when matched, + items: + type: string + type: array + receiver: + description: |- + Name of the receiver for this route. If not empty, it should be listed in + the `receivers` field. + type: string + repeatInterval: + description: |- + How long to wait before repeating the last notification. + Must match the regular expression`^(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?$` + Example: "4h" + type: string + routes: + description: Child routes. + items: + x-kubernetes-preserve-unknown-fields: true + type: array + type: object + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagers.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagers.yaml new file mode 100644 index 000000000..bc344481b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-alertmanagers.yaml @@ -0,0 +1,7839 @@ +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_alertmanagers.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + operator.prometheus.io/version: 0.74.0 + name: alertmanagers.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: Alertmanager + listKind: AlertmanagerList + plural: alertmanagers + shortNames: + - am + singular: alertmanager + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The version of Alertmanager + jsonPath: .spec.version + name: Version + type: string + - description: The number of desired replicas + jsonPath: .spec.replicas + name: Replicas + type: integer + - description: The number of ready replicas + jsonPath: .status.availableReplicas + name: Ready + type: integer + - jsonPath: .status.conditions[?(@.type == 'Reconciled')].status + name: Reconciled + type: string + - jsonPath: .status.conditions[?(@.type == 'Available')].status + name: Available + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Whether the resource reconciliation is paused or not + jsonPath: .status.paused + name: Paused + priority: 1 + type: boolean + name: v1 + schema: + openAPIV3Schema: + description: Alertmanager describes an Alertmanager cluster. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + Specification of the desired behavior of the Alertmanager cluster. More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + additionalPeers: + description: AdditionalPeers allows injecting a set of additional + Alertmanagers to peer with to form a highly available cluster. + items: + type: string + type: array + affinity: + description: If specified, the pod's scheduling constraints. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the + pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the + corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding + nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate + this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. + avoid putting this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + alertmanagerConfigMatcherStrategy: + description: |- + The AlertmanagerConfigMatcherStrategy defines how AlertmanagerConfig objects match the alerts. + In the future more options may be added. + properties: + type: + default: OnNamespace + description: |- + If set to `OnNamespace`, the operator injects a label matcher matching the namespace of the AlertmanagerConfig object for all its routes and inhibition rules. + `None` will not add any additional matchers other than the ones specified in the AlertmanagerConfig. + Default is `OnNamespace`. + enum: + - OnNamespace + - None + type: string + type: object + alertmanagerConfigNamespaceSelector: + description: |- + Namespaces to be selected for AlertmanagerConfig discovery. If nil, only + check own namespace. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + alertmanagerConfigSelector: + description: AlertmanagerConfigs to be selected for to merge and configure + Alertmanager with. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + alertmanagerConfiguration: + description: |- + alertmanagerConfiguration specifies the configuration of Alertmanager. + + + If defined, it takes precedence over the `configSecret` field. + + + This is an *experimental feature*, it may change in any upcoming release + in a breaking way. + properties: + global: + description: Defines the global parameters of the Alertmanager + configuration. + properties: + httpConfig: + description: HTTP client configuration. + properties: + authorization: + description: |- + Authorization header configuration for the client. + This is mutually exclusive with BasicAuth and is only available starting from Alertmanager v0.22+. + properties: + credentials: + description: Selects a key of a Secret in the namespace + that contains the credentials for authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth for the client. + This is mutually exclusive with Authorization. If both are defined, BasicAuth takes precedence. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + The secret's key that contains the bearer token to be used by the client + for authentication. + The secret needs to be in the same namespace as the Alertmanager + object and accessible by the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + followRedirects: + description: FollowRedirects specifies whether the client + should follow HTTP 3xx redirects. + type: boolean + oauth2: + description: OAuth2 client credentials used to fetch a + token for the targets. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to use + for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for + the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes used + for the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to fetch + the token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + proxyURL: + description: Optional proxy URL. + type: string + tlsConfig: + description: TLS configuration for the client. + properties: + ca: + description: Certificate authority used when verifying + server certificates. + properties: + configMap: + description: ConfigMap containing data to use + for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for + the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when doing + client-authentication. + properties: + configMap: + description: ConfigMap containing data to use + for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap + or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for + the targets. + properties: + key: + description: The key of the secret to select + from. Must be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key file + for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the targets. + type: string + type: object + type: object + opsGenieApiKey: + description: The default OpsGenie API Key. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + opsGenieApiUrl: + description: The default OpsGenie API URL. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + pagerdutyUrl: + description: The default Pagerduty URL. + type: string + resolveTimeout: + description: |- + ResolveTimeout is the default value used by alertmanager if the alert does + not include EndsAt, after this time passes it can declare the alert as resolved if it has not been updated. + This has no impact on alerts from Prometheus, as they always include EndsAt. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + slackApiUrl: + description: The default Slack API URL. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + smtp: + description: Configures global SMTP parameters. + properties: + authIdentity: + description: SMTP Auth using PLAIN + type: string + authPassword: + description: SMTP Auth using LOGIN and PLAIN. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + authSecret: + description: SMTP Auth using CRAM-MD5. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + authUsername: + description: SMTP Auth using CRAM-MD5, LOGIN and PLAIN. + If empty, Alertmanager doesn't authenticate to the SMTP + server. + type: string + from: + description: The default SMTP From header field. + type: string + hello: + description: The default hostname to identify to the SMTP + server. + type: string + requireTLS: + description: |- + The default SMTP TLS requirement. + Note that Go does not support unencrypted connections to remote SMTP endpoints. + type: boolean + smartHost: + description: The default SMTP smarthost used for sending + emails. + properties: + host: + description: Defines the host's address, it can be + a DNS name or a literal IP address. + minLength: 1 + type: string + port: + description: Defines the host's port, it can be a + literal port number or a port name. + minLength: 1 + type: string + required: + - host + - port + type: object + type: object + type: object + name: + description: |- + The name of the AlertmanagerConfig resource which is used to generate the Alertmanager configuration. + It must be defined in the same namespace as the Alertmanager object. + The operator will not enforce a `namespace` label for routes and inhibition rules. + minLength: 1 + type: string + templates: + description: Custom notification templates. + items: + description: SecretOrConfigMap allows to specify data as a Secret + or ConfigMap. Fields are mutually exclusive. + properties: + configMap: + description: ConfigMap containing data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + type: array + type: object + automountServiceAccountToken: + description: |- + AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in the pod. + If the service account has `automountServiceAccountToken: true`, set the field to `false` to opt out of automounting API credentials. + type: boolean + baseImage: + description: |- + Base image that is used to deploy pods, without tag. + Deprecated: use 'image' instead. + type: string + clusterAdvertiseAddress: + description: |- + ClusterAdvertiseAddress is the explicit address to advertise in cluster. + Needs to be provided for non RFC1918 [1] (public) addresses. + [1] RFC1918: https://tools.ietf.org/html/rfc1918 + type: string + clusterGossipInterval: + description: Interval between gossip attempts. + pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + clusterLabel: + description: |- + Defines the identifier that uniquely identifies the Alertmanager cluster. + You should only set it when the Alertmanager cluster includes Alertmanager instances which are external to this Alertmanager resource. In practice, the addresses of the external instances are provided via the `.spec.additionalPeers` field. + type: string + clusterPeerTimeout: + description: Timeout for cluster peering. + pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + clusterPushpullInterval: + description: Interval between pushpull attempts. + pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + configMaps: + description: |- + ConfigMaps is a list of ConfigMaps in the same namespace as the Alertmanager + object, which shall be mounted into the Alertmanager Pods. + Each ConfigMap is added to the StatefulSet definition as a volume named `configmap-`. + The ConfigMaps are mounted into `/etc/alertmanager/configmaps/` in the 'alertmanager' container. + items: + type: string + type: array + configSecret: + description: |- + ConfigSecret is the name of a Kubernetes Secret in the same namespace as the + Alertmanager object, which contains the configuration for this Alertmanager + instance. If empty, it defaults to `alertmanager-`. + + + The Alertmanager configuration should be available under the + `alertmanager.yaml` key. Additional keys from the original secret are + copied to the generated secret and mounted into the + `/etc/alertmanager/config` directory in the `alertmanager` container. + + + If either the secret or the `alertmanager.yaml` key is missing, the + operator provisions a minimal Alertmanager configuration with one empty + receiver (effectively dropping alert notifications). + type: string + containers: + description: |- + Containers allows injecting additional containers. This is meant to + allow adding an authentication proxy to an Alertmanager pod. + Containers described here modify an operator generated container if they + share the same name and modifications are done via a strategic merge + patch. The current container names are: `alertmanager` and + `config-reloader`. Overriding containers is entirely outside the scope + of what the maintainers will support and by doing so, you accept that + this behaviour may break at any time without notice. + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This field may only be set for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Setting the RestartPolicy as "Always" for the init container will have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default is DefaultProcMount which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + enableFeatures: + description: |- + Enable access to Alertmanager feature flags. By default, no features are enabled. + Enabling features which are disabled by default is entirely outside the + scope of what the maintainers will support and by doing so, you accept + that this behaviour may break at any time without notice. + + + It requires Alertmanager >= 0.27.0. + items: + type: string + type: array + externalUrl: + description: |- + The external URL the Alertmanager instances will be available under. This is + necessary to generate correct URLs. This is necessary if Alertmanager is not + served from root of a DNS name. + type: string + forceEnableClusterMode: + description: |- + ForceEnableClusterMode ensures Alertmanager does not deactivate the cluster mode when running with a single replica. + Use case is e.g. spanning an Alertmanager cluster across Kubernetes clusters with a single replica in each. + type: boolean + hostAliases: + description: Pods' hostAliases configuration + items: + description: |- + HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the + pod's hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + ip: + description: IP address of the host file entry. + type: string + required: + - hostnames + - ip + type: object + type: array + x-kubernetes-list-map-keys: + - ip + x-kubernetes-list-type: map + image: + description: |- + Image if specified has precedence over baseImage, tag and sha + combinations. Specifying the version is still necessary to ensure the + Prometheus Operator knows what version of Alertmanager is being + configured. + type: string + imagePullPolicy: + description: |- + Image pull policy for the 'alertmanager', 'init-config-reloader' and 'config-reloader' containers. + See https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy for more details. + enum: + - "" + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: |- + An optional list of references to secrets in the same namespace + to use for pulling prometheus and alertmanager images from registries + see http://kubernetes.io/docs/user-guide/images#specifying-imagepullsecrets-on-a-pod + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + description: |- + InitContainers allows adding initContainers to the pod definition. Those can be used to e.g. + fetch secrets for injection into the Alertmanager configuration from external sources. Any + errors during the execution of an initContainer will lead to a restart of the Pod. More info: https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + InitContainers described here modify an operator + generated init containers if they share the same name and modifications are + done via a strategic merge patch. The current init container name is: + `init-config-reloader`. Overriding init containers is entirely outside the + scope of what the maintainers will support and by doing so, you accept that + this behaviour may break at any time without notice. + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This field may only be set for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Setting the RestartPolicy as "Always" for the init container will have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default is DefaultProcMount which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + listenLocal: + description: |- + ListenLocal makes the Alertmanager server listen on loopback, so that it + does not bind against the Pod IP. Note this is only for the Alertmanager + UI, not the gossip communication. + type: boolean + logFormat: + description: Log format for Alertmanager to be configured with. + enum: + - "" + - logfmt + - json + type: string + logLevel: + description: Log level for Alertmanager to be configured with. + enum: + - "" + - debug + - info + - warn + - error + type: string + minReadySeconds: + description: |- + Minimum number of seconds for which a newly created pod should be ready + without any of its container crashing for it to be considered available. + Defaults to 0 (pod will be considered available as soon as it is ready) + This is an alpha field from kubernetes 1.22 until 1.24 which requires enabling the StatefulSetMinReadySeconds feature gate. + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + description: Define which Nodes the Pods are scheduled on. + type: object + paused: + description: |- + If set to true all actions on the underlying managed objects are not + goint to be performed, except for delete actions. + type: boolean + podMetadata: + description: |- + PodMetadata configures labels and annotations which are propagated to the Alertmanager pods. + + + The following items are reserved and cannot be overridden: + * "alertmanager" label, set to the name of the Alertmanager instance. + * "app.kubernetes.io/instance" label, set to the name of the Alertmanager instance. + * "app.kubernetes.io/managed-by" label, set to "prometheus-operator". + * "app.kubernetes.io/name" label, set to "alertmanager". + * "app.kubernetes.io/version" label, set to the Alertmanager version. + * "kubectl.kubernetes.io/default-container" annotation, set to "alertmanager". + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: http://kubernetes.io/docs/user-guide/annotations + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + More info: http://kubernetes.io/docs/user-guide/labels + type: object + name: + description: |- + Name must be unique within a namespace. Is required when creating resources, although + some resources may allow a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence and configuration + definition. + Cannot be updated. + More info: http://kubernetes.io/docs/user-guide/identifiers#names + type: string + type: object + portName: + default: web + description: |- + Port name used for the pods and governing service. + Defaults to `web`. + type: string + priorityClassName: + description: Priority class assigned to the Pods + type: string + replicas: + description: |- + Size is the expected size of the alertmanager cluster. The controller will + eventually make the size of the running cluster equal to the expected + size. + format: int32 + type: integer + resources: + description: Define resources requests and limits for single Pods. + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + retention: + default: 120h + description: |- + Time duration Alertmanager shall retain data for. Default is '120h', + and must match the regular expression `[0-9]+(ms|s|m|h)` (milliseconds seconds minutes hours). + pattern: ^(0|(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + routePrefix: + description: |- + The route prefix Alertmanager registers HTTP handlers for. This is useful, + if using ExternalURL and a proxy is rewriting HTTP routes of a request, + and the actual ExternalURL is still true, but the server serves requests + under a different route prefix. For example for use with `kubectl proxy`. + type: string + secrets: + description: |- + Secrets is a list of Secrets in the same namespace as the Alertmanager + object, which shall be mounted into the Alertmanager Pods. + Each Secret is added to the StatefulSet definition as a volume named `secret-`. + The Secrets are mounted into `/etc/alertmanager/secrets/` in the 'alertmanager' container. + items: + type: string + type: array + securityContext: + description: |- + SecurityContext holds pod-level security attributes and common container settings. + This defaults to the default PodSecurityContext. + properties: + fsGroup: + description: |- + A special supplemental group that applies to all containers in a pod. + Some volume types allow the Kubelet to change the ownership of that volume + to be owned by the pod: + + + 1. The owning GID will be the FSGroup + 2. The setgid bit is set (new files created in the volume will be owned by FSGroup) + 3. The permission bits are OR'd with rw-rw---- + + + If unset, the Kubelet will not modify the ownership and permissions of any volume. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + fsGroupChangePolicy: + description: |- + fsGroupChangePolicy defines behavior of changing ownership and permission of the volume + before being exposed inside Pod. This field will only apply to + volume types which support fsGroup based ownership(and permissions). + It will have no effect on ephemeral volume types such as: secret, configmaps + and emptydir. + Valid values are "OnRootMismatch" and "Always". If not specified, "Always" is used. + Note that this field cannot be set when spec.os.name is windows. + type: string + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in SecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence + for that container. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to all containers. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the value specified in SecurityContext + takes precedence for that container. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies to + the container. + type: string + role: + description: Role is a SELinux role label that applies to + the container. + type: string + type: + description: Type is a SELinux type label that applies to + the container. + type: string + user: + description: User is a SELinux user label that applies to + the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by the containers in this pod. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + supplementalGroups: + description: |- + A list of groups applied to the first process run in each container, in addition + to the container's primary GID, the fsGroup (if specified), and group memberships + defined in the container image for the uid of the container process. If unspecified, + no additional groups are added to any container. Note that group memberships + defined in the container image for the uid of the container process are still effective, + even if they are not included in this list. + Note that this field cannot be set when spec.os.name is windows. + items: + format: int64 + type: integer + type: array + sysctls: + description: |- + Sysctls hold a list of namespaced sysctls used for the pod. Pods with unsupported + sysctls (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name is windows. + items: + description: Sysctl defines a kernel parameter to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the GMSA + credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + serviceAccountName: + description: |- + ServiceAccountName is the name of the ServiceAccount to use to run the + Prometheus Pods. + type: string + sha: + description: |- + SHA of Alertmanager container image to be deployed. Defaults to the value of `version`. + Similar to a tag, but the SHA explicitly deploys an immutable container image. + Version and Tag are ignored if SHA is set. + Deprecated: use 'image' instead. The image digest can be specified as part of the image URL. + type: string + storage: + description: |- + Storage is the definition of how storage will be used by the Alertmanager + instances. + properties: + disableMountSubPath: + description: 'Deprecated: subPath usage will be removed in a future + release.' + type: boolean + emptyDir: + description: |- + EmptyDirVolumeSource to be used by the StatefulSet. + If specified, it takes precedence over `ephemeral` and `volumeClaimTemplate`. + More info: https://kubernetes.io/docs/concepts/storage/volumes/#emptydir + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: |- + EphemeralVolumeSource to be used by the StatefulSet. + This is a beta field in k8s 1.21 and GA in 1.15. + For lower versions, starting with k8s 1.19, it requires enabling the GenericEphemeralVolume feature gate. + More info: https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/#generic-ephemeral-volumes + properties: + volumeClaimTemplate: + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + + Required, must not be nil. + properties: + metadata: + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. + type: object + spec: + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over volumes + to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass + will be applied to the claim but it's not allowed to reset this field to empty string once it is set. + If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass + will be set by the persistentvolume controller if it exists. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#volumeattributesclass + (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference to + the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + volumeClaimTemplate: + description: |- + Defines the PVC spec to be used by the Prometheus StatefulSets. + The easiest way to use a volume that cannot be automatically provisioned + is to use a label selector alongside manually created PersistentVolumes. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + description: EmbeddedMetadata contains metadata relevant to + an EmbeddedResource. + properties: + annotations: + additionalProperties: + type: string + description: |- + Annotations is an unstructured key value map stored with a resource that may be + set by external tools to store and retrieve arbitrary metadata. They are not + queryable and should be preserved when modifying objects. + More info: http://kubernetes.io/docs/user-guide/annotations + type: object + labels: + additionalProperties: + type: string + description: |- + Map of string keys and values that can be used to organize and categorize + (scope and select) objects. May match selectors of replication controllers + and services. + More info: http://kubernetes.io/docs/user-guide/labels + type: object + name: + description: |- + Name must be unique within a namespace. Is required when creating resources, although + some resources may allow a client to request the generation of an appropriate name + automatically. Name is primarily intended for creation idempotence and configuration + definition. + Cannot be updated. + More info: http://kubernetes.io/docs/user-guide/identifiers#names + type: string + type: object + spec: + description: |- + Defines the desired characteristics of a volume requested by a pod author. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being referenced + type: string + name: + description: Name is the name of resource being referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over volumes to + consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass + will be applied to the claim but it's not allowed to reset this field to empty string once it is set. + If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass + will be set by the persistentvolume controller if it exists. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#volumeattributesclass + (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference to the + PersistentVolume backing this claim. + type: string + type: object + status: + description: 'Deprecated: this field is never set.' + properties: + accessModes: + description: |- + accessModes contains the actual access modes the volume backing the PVC has. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + allocatedResourceStatuses: + additionalProperties: + description: |- + When a controller receives persistentvolume claim update with ClaimResourceStatus for a resource + that it does not recognizes, then it should ignore that update and let other controllers + handle it. + type: string + description: "allocatedResourceStatuses stores status + of resource being resized for the given PVC.\nKey names + follow standard Kubernetes label syntax. Valid values + are either:\n\t* Un-prefixed keys:\n\t\t- storage - + the capacity of the volume.\n\t* Custom resources must + use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart + from above values - keys that are unprefixed or have + kubernetes.io prefix are considered\nreserved and hence + may not be used.\n\n\nClaimResourceStatus can be in + any of following states:\n\t- ControllerResizeInProgress:\n\t\tState + set when resize controller starts resizing the volume + in control-plane.\n\t- ControllerResizeFailed:\n\t\tState + set when resize has failed in resize controller with + a terminal error.\n\t- NodeResizePending:\n\t\tState + set when resize controller has finished resizing the + volume but further resizing of\n\t\tvolume is needed + on the node.\n\t- NodeResizeInProgress:\n\t\tState set + when kubelet starts resizing the volume.\n\t- NodeResizeFailed:\n\t\tState + set when resizing has failed in kubelet with a terminal + error. Transient errors don't set\n\t\tNodeResizeFailed.\nFor + example: if expanding a PVC for more capacity - this + field can be one of the following states:\n\t- pvc.status.allocatedResourceStatus['storage'] + = \"ControllerResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] + = \"ControllerResizeFailed\"\n - pvc.status.allocatedResourceStatus['storage'] + = \"NodeResizePending\"\n - pvc.status.allocatedResourceStatus['storage'] + = \"NodeResizeInProgress\"\n - pvc.status.allocatedResourceStatus['storage'] + = \"NodeResizeFailed\"\nWhen this field is not set, + it means that no resize operation is in progress for + the given PVC.\n\n\nA controller that receives PVC update + with previously unknown resourceName or ClaimResourceStatus\nshould + ignore the update for the purpose it was designed. For + example - a controller that\nonly is responsible for + resizing capacity of the volume, should ignore PVC updates + that change other valid\nresources associated with PVC.\n\n\nThis + is an alpha field and requires enabling RecoverVolumeExpansionFailure + feature." + type: object + x-kubernetes-map-type: granular + allocatedResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: "allocatedResources tracks the resources + allocated to a PVC including its capacity.\nKey names + follow standard Kubernetes label syntax. Valid values + are either:\n\t* Un-prefixed keys:\n\t\t- storage - + the capacity of the volume.\n\t* Custom resources must + use implementation-defined prefixed names such as \"example.com/my-custom-resource\"\nApart + from above values - keys that are unprefixed or have + kubernetes.io prefix are considered\nreserved and hence + may not be used.\n\n\nCapacity reported here may be + larger than the actual capacity when a volume expansion + operation\nis requested.\nFor storage quota, the larger + value from allocatedResources and PVC.spec.resources + is used.\nIf allocatedResources is not set, PVC.spec.resources + alone is used for quota calculation.\nIf a volume expansion + capacity request is lowered, allocatedResources is only\nlowered + if there are no expansion operations in progress and + if the actual volume capacity\nis equal or lower than + the requested capacity.\n\n\nA controller that receives + PVC update with previously unknown resourceName\nshould + ignore the update for the purpose it was designed. For + example - a controller that\nonly is responsible for + resizing capacity of the volume, should ignore PVC updates + that change other valid\nresources associated with PVC.\n\n\nThis + is an alpha field and requires enabling RecoverVolumeExpansionFailure + feature." + type: object + capacity: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: capacity represents the actual resources + of the underlying volume. + type: object + conditions: + description: |- + conditions is the current Condition of persistent volume claim. If underlying persistent volume is being + resized then the Condition will be set to 'ResizeStarted'. + items: + description: PersistentVolumeClaimCondition contains + details about state of pvc + properties: + lastProbeTime: + description: lastProbeTime is the time we probed + the condition. + format: date-time + type: string + lastTransitionTime: + description: lastTransitionTime is the time the + condition transitioned from one status to another. + format: date-time + type: string + message: + description: message is the human-readable message + indicating details about last transition. + type: string + reason: + description: |- + reason is a unique, this should be a short, machine understandable string that gives the reason + for condition's last transition. If it reports "ResizeStarted" that means the underlying + persistent volume is being resized. + type: string + status: + type: string + type: + description: PersistentVolumeClaimConditionType + is a valid value of PersistentVolumeClaimCondition.Type + type: string + required: + - status + - type + type: object + type: array + currentVolumeAttributesClassName: + description: |- + currentVolumeAttributesClassName is the current name of the VolumeAttributesClass the PVC is using. + When unset, there is no VolumeAttributeClass applied to this PersistentVolumeClaim + This is an alpha field and requires enabling VolumeAttributesClass feature. + type: string + modifyVolumeStatus: + description: |- + ModifyVolumeStatus represents the status object of ControllerModifyVolume operation. + When this is unset, there is no ModifyVolume operation being attempted. + This is an alpha field and requires enabling VolumeAttributesClass feature. + properties: + status: + description: "status is the status of the ControllerModifyVolume + operation. It can be in any of following states:\n + - Pending\n Pending indicates that the PersistentVolumeClaim + cannot be modified due to unmet requirements, such + as\n the specified VolumeAttributesClass not existing.\n + - InProgress\n InProgress indicates that the volume + is being modified.\n - Infeasible\n Infeasible + indicates that the request has been rejected as + invalid by the CSI driver. To\n\t resolve the error, + a valid VolumeAttributesClass needs to be specified.\nNote: + New statuses can be added in the future. Consumers + should check for unknown statuses and fail appropriately." + type: string + targetVolumeAttributesClassName: + description: targetVolumeAttributesClassName is the + name of the VolumeAttributesClass the PVC currently + being reconciled + type: string + required: + - status + type: object + phase: + description: phase represents the current phase of PersistentVolumeClaim. + type: string + type: object + type: object + type: object + tag: + description: |- + Tag of Alertmanager container image to be deployed. Defaults to the value of `version`. + Version is ignored if Tag is set. + Deprecated: use 'image' instead. The image tag can be specified as part of the image URL. + type: string + tolerations: + description: If specified, the pod's tolerations. + items: + description: |- + The pod this Toleration is attached to tolerates any taint that matches + the triple using the matching operator . + properties: + effect: + description: |- + Effect indicates the taint effect to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, PreferNoSchedule and NoExecute. + type: string + key: + description: |- + Key is the taint key that the toleration applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; this combination means to match all values and all keys. + type: string + operator: + description: |- + Operator represents a key's relationship to the value. + Valid operators are Exists and Equal. Defaults to Equal. + Exists is equivalent to wildcard for value, so that a pod can + tolerate all taints of a particular category. + type: string + tolerationSeconds: + description: |- + TolerationSeconds represents the period of time the toleration (which must be + of effect NoExecute, otherwise this field is ignored) tolerates the taint. By default, + it is not set, which means tolerate the taint forever (do not evict). Zero and + negative values will be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: |- + Value is the taint value the toleration matches to. + If the operator is Exists, the value should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: If specified, the pod's topology spread constraints. + items: + description: TopologySpreadConstraint specifies how to spread matching + pods among the given topology. + properties: + labelSelector: + description: |- + LabelSelector is used to find matching pods. + Pods that match this label selector are counted to determine the number of pods + in their corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select the pods over which + spreading will be calculated. The keys are used to lookup values from the + incoming pod labels, those key-value labels are ANDed with labelSelector + to select the group of existing pods over which spreading will be calculated + for the incoming pod. The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + MatchLabelKeys cannot be set when LabelSelector isn't set. + Keys that don't exist in the incoming pod labels will + be ignored. A null or empty list means only match against labelSelector. + + + This is a beta field and requires the MatchLabelKeysInPodTopologySpread feature gate to be enabled (enabled by default). + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: |- + MaxSkew describes the degree to which pods may be unevenly distributed. + When `whenUnsatisfiable=DoNotSchedule`, it is the maximum permitted difference + between the number of matching pods in the target topology and the global minimum. + The global minimum is the minimum number of matching pods in an eligible domain + or zero if the number of eligible domains is less than MinDomains. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 2/2/1: + In this case, the global minimum is 1. + | zone1 | zone2 | zone3 | + | P P | P P | P | + - if MaxSkew is 1, incoming pod can only be scheduled to zone3 to become 2/2/2; + scheduling it onto zone1(zone2) would make the ActualSkew(3-1) on zone1(zone2) + violate MaxSkew(1). + - if MaxSkew is 2, incoming pod can be scheduled onto any zone. + When `whenUnsatisfiable=ScheduleAnyway`, it is used to give higher precedence + to topologies that satisfy it. + It's a required field. Default value is 1 and 0 is not allowed. + format: int32 + type: integer + minDomains: + description: |- + MinDomains indicates a minimum number of eligible domains. + When the number of eligible domains with matching topology keys is less than minDomains, + Pod Topology Spread treats "global minimum" as 0, and then the calculation of Skew is performed. + And when the number of eligible domains with matching topology keys equals or greater than minDomains, + this value has no effect on scheduling. + As a result, when the number of eligible domains is less than minDomains, + scheduler won't schedule more than maxSkew Pods to those domains. + If value is nil, the constraint behaves as if MinDomains is equal to 1. + Valid values are integers greater than 0. + When value is not nil, WhenUnsatisfiable must be DoNotSchedule. + + + For example, in a 3-zone cluster, MaxSkew is set to 2, MinDomains is set to 5 and pods with the same + labelSelector spread as 2/2/2: + | zone1 | zone2 | zone3 | + | P P | P P | P P | + The number of domains is less than 5(MinDomains), so "global minimum" is treated as 0. + In this situation, new pod with the same labelSelector cannot be scheduled, + because computed skew will be 3(3 - 0) if new Pod is scheduled to any of the three zones, + it will violate MaxSkew. + + + This is a beta field and requires the MinDomainsInPodTopologySpread feature gate to be enabled (enabled by default). + format: int32 + type: integer + nodeAffinityPolicy: + description: |- + NodeAffinityPolicy indicates how we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew. Options are: + - Honor: only nodes matching nodeAffinity/nodeSelector are included in the calculations. + - Ignore: nodeAffinity/nodeSelector are ignored. All nodes are included in the calculations. + + + If this value is nil, the behavior is equivalent to the Honor policy. + This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. + type: string + nodeTaintsPolicy: + description: |- + NodeTaintsPolicy indicates how we will treat node taints when calculating + pod topology spread skew. Options are: + - Honor: nodes without taints, along with tainted nodes for which the incoming pod + has a toleration, are included. + - Ignore: node taints are ignored. All nodes are included. + + + If this value is nil, the behavior is equivalent to the Ignore policy. + This is a beta-level feature default enabled by the NodeInclusionPolicyInPodTopologySpread feature flag. + type: string + topologyKey: + description: |- + TopologyKey is the key of node labels. Nodes that have a label with this key + and identical values are considered to be in the same topology. + We consider each as a "bucket", and try to put balanced number + of pods into each bucket. + We define a domain as a particular instance of a topology. + Also, we define an eligible domain as a domain whose nodes meet the requirements of + nodeAffinityPolicy and nodeTaintsPolicy. + e.g. If TopologyKey is "kubernetes.io/hostname", each Node is a domain of that topology. + And, if TopologyKey is "topology.kubernetes.io/zone", each zone is a domain of that topology. + It's a required field. + type: string + whenUnsatisfiable: + description: |- + WhenUnsatisfiable indicates how to deal with a pod if it doesn't satisfy + the spread constraint. + - DoNotSchedule (default) tells the scheduler not to schedule it. + - ScheduleAnyway tells the scheduler to schedule the pod in any location, + but giving higher precedence to topologies that would help reduce the + skew. + A constraint is considered "Unsatisfiable" for an incoming pod + if and only if every possible node assignment for that pod would violate + "MaxSkew" on some topology. + For example, in a 3-zone cluster, MaxSkew is set to 1, and pods with the same + labelSelector spread as 3/1/1: + | zone1 | zone2 | zone3 | + | P P P | P | P | + If WhenUnsatisfiable is set to DoNotSchedule, incoming pod can only be scheduled + to zone2(zone3) to become 3/2/1(3/1/2) as ActualSkew(2-1) on zone2(zone3) satisfies + MaxSkew(1). In other words, the cluster can still be imbalanced, but scheduler + won't make it *more* imbalanced. + It's a required field. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + version: + description: Version the cluster should be on. + type: string + volumeMounts: + description: |- + VolumeMounts allows configuration of additional VolumeMounts on the output StatefulSet definition. + VolumeMounts specified will be appended to other VolumeMounts in the alertmanager container, + that are generated as a result of StorageSpec objects. + items: + description: VolumeMount describes a mounting of a Volume within + a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + volumes: + description: |- + Volumes allows configuration of additional volumes on the output StatefulSet definition. + Volumes specified will be appended to other volumes that are generated as a result of + StorageSpec objects. + items: + description: Volume represents a named volume in a pod that may + be accessed by any container in the pod. + properties: + awsElasticBlockStore: + description: |- + awsElasticBlockStore represents an AWS Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + format: int32 + type: integer + readOnly: + description: |- + readOnly value true will force the readOnly setting in VolumeMounts. + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: boolean + volumeID: + description: |- + volumeID is unique ID of the persistent disk resource in AWS (Amazon EBS volume). + More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data Disk mount on + the host and bind mount to the pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching mode: None, + Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data disk in the + blob storage + type: string + diskURI: + description: diskURI is the URI of data disk in the blob + storage + type: string + fsType: + description: |- + fsType is Filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: multiple + blob disks per storage account Dedicated: single blob + disk per storage account Managed: azure managed data + disk (only in managed availability set). defaults to shared' + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File Service mount + on the host and bind mount to the pod. + properties: + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret that contains + Azure Storage Account Name and Key + type: string + shareName: + description: shareName is the azure share Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount on the host that + shares a pod's lifetime + properties: + monitors: + description: |- + monitors is Required: Monitors is a collection of Ceph monitors + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + items: + type: string + type: array + path: + description: 'path is Optional: Used as the mounted root, + rather than the full Ceph tree, default is /' + type: string + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: boolean + secretFile: + description: |- + secretFile is Optional: SecretFile is the path to key ring for User, default is /etc/ceph/user.secret + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + secretRef: + description: |- + secretRef is Optional: SecretRef is reference to the authentication secret for User, default is empty. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: |- + user is optional: User is the rados user name, default is admin + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it + type: string + required: + - monitors + type: object + cinder: + description: |- + cinder represents a cinder volume attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: boolean + secretRef: + description: |- + secretRef is optional: points to a secret object containing parameters used to connect + to OpenStack. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: |- + volumeID used to identify the volume in cinder. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap that should populate + this volume + properties: + defaultMode: + description: |- + defaultMode is optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: optional specify whether the ConfigMap or its + keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) represents ephemeral + storage that is handled by certain external CSI drivers (Beta + feature). + properties: + driver: + description: |- + driver is the name of the CSI driver that handles this volume. + Consult with your admin for the correct name as registered in the cluster. + type: string + fsType: + description: |- + fsType to mount. Ex. "ext4", "xfs", "ntfs". + If not provided, the empty value is passed to the associated CSI driver + which will determine the default filesystem to apply. + type: string + nodePublishSecretRef: + description: |- + nodePublishSecretRef is a reference to the secret object containing + sensitive information to pass to the CSI driver to complete the CSI + NodePublishVolume and NodeUnpublishVolume calls. + This field is optional, and may be empty if no secret is required. If the + secret object contains more than one secret, all secret references are passed. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: |- + readOnly specifies a read-only configuration for the volume. + Defaults to false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: |- + volumeAttributes stores driver-specific properties that are passed to the CSI + driver. Consult your driver's documentation for supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API about the pod + that should populate this volume + properties: + defaultMode: + description: |- + Optional: mode bits to use on created files by default. Must be a + Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: Items is a list of downward API volume file + items: + description: DownwardAPIVolumeFile represents information + to create the file containing the pod field + properties: + fieldRef: + description: 'Required: Selects a field of the pod: + only annotations, labels, name and namespace are + supported.' + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the relative path + name of the file to be created. Must not be absolute + or contain the ''..'' path. Must be utf-8 encoded. + The first item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: |- + emptyDir represents a temporary directory that shares a pod's lifetime. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + properties: + medium: + description: |- + medium represents what type of storage medium should back this directory. + The default is "" which means to use the node's default medium. + Must be an empty string (default) or Memory. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: |- + sizeLimit is the total amount of local storage required for this EmptyDir volume. + The size limit is also applicable for memory medium. + The maximum usage on memory medium EmptyDir would be the minimum value between + the SizeLimit specified here and the sum of memory limits of all containers in a pod. + The default is nil which means that the limit is undefined. + More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: |- + ephemeral represents a volume that is handled by a cluster storage driver. + The volume's lifecycle is tied to the pod that defines it - it will be created before the pod starts, + and deleted when the pod is removed. + + + Use this if: + a) the volume is only needed while the pod runs, + b) features of normal volumes like restoring from snapshot or capacity + tracking are needed, + c) the storage driver is specified through a storage class, and + d) the storage driver supports dynamic volume provisioning through + a PersistentVolumeClaim (see EphemeralVolumeSource for more + information on the connection between this volume type + and PersistentVolumeClaim). + + + Use PersistentVolumeClaim or one of the vendor-specific + APIs for volumes that persist for longer than the lifecycle + of an individual pod. + + + Use CSI for light-weight local ephemeral volumes if the CSI driver is meant to + be used that way - see the documentation of the driver for + more information. + + + A pod can use both types of ephemeral volumes and + persistent volumes at the same time. + properties: + volumeClaimTemplate: + description: |- + Will be used to create a stand-alone PVC to provision the volume. + The pod in which this EphemeralVolumeSource is embedded will be the + owner of the PVC, i.e. the PVC will be deleted together with the + pod. The name of the PVC will be `-` where + `` is the name from the `PodSpec.Volumes` array + entry. Pod validation will reject the pod if the concatenated name + is not valid for a PVC (for example, too long). + + + An existing PVC with that name that is not owned by the pod + will *not* be used for the pod to avoid using an unrelated + volume by mistake. Starting the pod is then blocked until + the unrelated PVC is removed. If such a pre-created PVC is + meant to be used by the pod, the PVC has to updated with an + owner reference to the pod once the pod exists. Normally + this should not be necessary, but it may be useful when + manually reconstructing a broken cluster. + + + This field is read-only and no changes will be made by Kubernetes + to the PVC after it has been created. + + + Required, must not be nil. + properties: + metadata: + description: |- + May contain labels and annotations that will be copied into the PVC + when creating it. No other fields are allowed and will be rejected during + validation. + type: object + spec: + description: |- + The specification for the PersistentVolumeClaim. The entire content is + copied unchanged into the PVC that gets created from this + template. The same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: |- + accessModes contains the desired access modes the volume should have. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1 + items: + type: string + type: array + dataSource: + description: |- + dataSource field can be used to specify either: + * An existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external controller can support the specified data source, + it will create a new volume based on the contents of the specified data source. + When the AnyVolumeDataSource feature gate is enabled, dataSource contents will be copied to dataSourceRef, + and dataSourceRef contents will be copied to dataSource when dataSourceRef.namespace is not specified. + If the namespace is specified, then dataSourceRef will not be copied to dataSource. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: |- + dataSourceRef specifies the object from which to populate the volume with data, if a non-empty + volume is desired. This may be any object from a non-empty API group (non + core object) or a PersistentVolumeClaim object. + When this field is specified, volume binding will only succeed if the type of + the specified object matches some installed volume populator or dynamic + provisioner. + This field will replace the functionality of the dataSource field and as such + if both fields are non-empty, they must have the same value. For backwards + compatibility, when namespace isn't specified in dataSourceRef, + both fields (dataSource and dataSourceRef) will be set to the same + value automatically if one of them is empty and the other is non-empty. + When namespace is specified in dataSourceRef, + dataSource isn't set to the same value and must be empty. + There are three important differences between dataSource and dataSourceRef: + * While dataSource only allows two specific types of objects, dataSourceRef + allows any non-core object, as well as PersistentVolumeClaim objects. + * While dataSource ignores disallowed values (dropping them), dataSourceRef + preserves all values, and generates an error if a disallowed value is + specified. + * While dataSource only allows local objects, dataSourceRef allows objects + in any namespaces. + (Beta) Using this field requires the AnyVolumeDataSource feature gate to be enabled. + (Alpha) Using the namespace field of dataSourceRef requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + properties: + apiGroup: + description: |- + APIGroup is the group for the resource being referenced. + If APIGroup is not specified, the specified Kind must be in the core API group. + For any other third-party types, APIGroup is required. + type: string + kind: + description: Kind is the type of resource being + referenced + type: string + name: + description: Name is the name of resource being + referenced + type: string + namespace: + description: |- + Namespace is the namespace of resource being referenced + Note that when a namespace is specified, a gateway.networking.k8s.io/ReferenceGrant object is required in the referent namespace to allow that namespace's owner to accept the reference. See the ReferenceGrant documentation for details. + (Alpha) This field requires the CrossNamespaceVolumeDataSource feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: |- + resources represents the minimum resources the volume should have. + If RecoverVolumeExpansionFailure feature is enabled users are allowed to specify resource requirements + that are lower than previous value but must still be higher than capacity recorded in the + status field of the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources + properties: + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + selector: + description: selector is a label query over volumes + to consider for binding. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: |- + storageClassName is the name of the StorageClass required by the claim. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1 + type: string + volumeAttributesClassName: + description: |- + volumeAttributesClassName may be used to set the VolumeAttributesClass used by this claim. + If specified, the CSI driver will create or update the volume with the attributes defined + in the corresponding VolumeAttributesClass. This has a different purpose than storageClassName, + it can be changed after the claim is created. An empty string value means that no VolumeAttributesClass + will be applied to the claim but it's not allowed to reset this field to empty string once it is set. + If unspecified and the PersistentVolumeClaim is unbound, the default VolumeAttributesClass + will be set by the persistentvolume controller if it exists. + If the resource referred to by volumeAttributesClass does not exist, this PersistentVolumeClaim will be + set to a Pending state, as reflected by the modifyVolumeStatus field, until such as a resource + exists. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#volumeattributesclass + (Alpha) Using this field requires the VolumeAttributesClass feature gate to be enabled. + type: string + volumeMode: + description: |- + volumeMode defines what type of volume is required by the claim. + Value of Filesystem is implied when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding reference + to the PersistentVolume backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource that is + attached to a kubelet's host machine and then exposed to the + pod. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + lun: + description: 'lun is Optional: FC target lun number' + format: int32 + type: integer + readOnly: + description: |- + readOnly is Optional: Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target worldwide + names (WWNs)' + items: + type: string + type: array + wwids: + description: |- + wwids Optional: FC volume world wide identifiers (wwids) + Either wwids or combination of targetWWNs and lun must be set, but not both simultaneously. + items: + type: string + type: array + type: object + flexVolume: + description: |- + flexVolume represents a generic volume resource that is + provisioned/attached using an exec based plugin. + properties: + driver: + description: driver is the name of the driver to use for + this volume. + type: string + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". The default filesystem depends on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field holds extra + command options if any.' + type: object + readOnly: + description: |- + readOnly is Optional: defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef is Optional: secretRef is reference to the secret object containing + sensitive information to pass to the plugin scripts. This may be + empty if no secret object is specified. If the secret object + contains more than one secret, all secrets are passed to the plugin + scripts. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume attached to + a kubelet's host machine. This depends on the Flocker control + service being running + properties: + datasetName: + description: |- + datasetName is Name of the dataset stored as metadata -> name on the dataset for Flocker + should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the dataset. This + is unique identifier of a Flocker dataset + type: string + type: object + gcePersistentDisk: + description: |- + gcePersistentDisk represents a GCE Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + properties: + fsType: + description: |- + fsType is filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + partition: + description: |- + partition is the partition in the volume that you want to mount. + If omitted, the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify the partition as "1". + Similarly, the volume partition for /dev/sda is "0" (or you can leave the property empty). + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + format: int32 + type: integer + pdName: + description: |- + pdName is unique name of the PD resource in GCE. Used to identify the disk in GCE. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + type: boolean + required: + - pdName + type: object + gitRepo: + description: |- + gitRepo represents a git repository at a particular revision. + DEPRECATED: GitRepo is deprecated. To provision a container with a git repo, mount an + EmptyDir into an InitContainer that clones the repo using git, then mount the EmptyDir + into the Pod's container. + properties: + directory: + description: |- + directory is the target directory name. + Must not contain or start with '..'. If '.' is supplied, the volume directory will be the + git repository. Otherwise, if specified, the volume will contain the git repository in + the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for the specified + revision. + type: string + required: + - repository + type: object + glusterfs: + description: |- + glusterfs represents a Glusterfs mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md + properties: + endpoints: + description: |- + endpoints is the endpoint name that details Glusterfs topology. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + path: + description: |- + path is the Glusterfs volume path. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: string + readOnly: + description: |- + readOnly here will force the Glusterfs volume to be mounted with read-only permissions. + Defaults to false. + More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: |- + hostPath represents a pre-existing file or directory on the host + machine that is directly exposed to the container. This is generally + used for system agents or other privileged things that are allowed + to see the host machine. Most containers will NOT need this. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + --- + TODO(jonesdl) We need to restrict who can use host directory mounts and who can/can not + mount host directories as read/write. + properties: + path: + description: |- + path of the directory on the host. + If the path is a symlink, it will follow the link to the real path. + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + type: + description: |- + type for HostPath Volume + Defaults to "" + More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + type: string + required: + - path + type: object + iscsi: + description: |- + iscsi represents an ISCSI Disk resource that is attached to a + kubelet's host machine and then exposed to the pod. + More info: https://examples.k8s.io/volumes/iscsi/README.md + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether support iSCSI + Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether support iSCSI + Session CHAP authentication + type: boolean + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + initiatorName: + description: |- + initiatorName is the custom iSCSI Initiator Name. + If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface + : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified Name. + type: string + iscsiInterface: + description: |- + iscsiInterface is the interface Name that uses an iSCSI transport. + Defaults to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun number. + format: int32 + type: integer + portals: + description: |- + portals is the iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret for iSCSI target + and initiator authentication + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: |- + targetPortal is iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port + is other than default (typically TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: |- + name of the volume. + Must be a DNS_LABEL and unique within the pod. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + type: string + nfs: + description: |- + nfs represents an NFS mount on the host that shares a pod's lifetime + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + properties: + path: + description: |- + path that is exported by the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + readOnly: + description: |- + readOnly here will force the NFS export to be mounted with read-only permissions. + Defaults to false. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: boolean + server: + description: |- + server is the hostname or IP address of the NFS server. + More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: |- + persistentVolumeClaimVolumeSource represents a reference to a + PersistentVolumeClaim in the same namespace. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + properties: + claimName: + description: |- + claimName is the name of a PersistentVolumeClaim in the same namespace as the pod using this volume. + More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims + type: string + readOnly: + description: |- + readOnly Will force the ReadOnly setting in VolumeMounts. + Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a PhotonController + persistent disk attached and mounted on kubelets host machine + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies Photon Controller + persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx volume attached + and mounted on kubelets host machine + properties: + fsType: + description: |- + fSType represents the filesystem type to mount + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources secrets, + configmaps, and downward API + properties: + defaultMode: + description: |- + defaultMode are the mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + sources: + description: sources is the list of volume projections + items: + description: Projection that may be projected along with + other supported volume types + properties: + clusterTrustBundle: + description: |- + ClusterTrustBundle allows a pod to access the `.spec.trustBundle` field + of ClusterTrustBundle objects in an auto-updating file. + + + Alpha, gated by the ClusterTrustBundleProjection feature gate. + + + ClusterTrustBundle objects can either be selected by name, or by the + combination of signer name and a label selector. + + + Kubelet performs aggressive normalization of the PEM contents written + into the pod filesystem. Esoteric PEM features such as inter-block + comments and block headers are stripped. Certificates are deduplicated. + The ordering of certificates within the file is arbitrary, and Kubelet + may change the order over time. + properties: + labelSelector: + description: |- + Select all ClusterTrustBundles that match this label selector. Only has + effect if signerName is set. Mutually-exclusive with name. If unset, + interpreted as "match nothing". If set but empty, interpreted as "match + everything". + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + name: + description: |- + Select a single ClusterTrustBundle by object name. Mutually-exclusive + with signerName and labelSelector. + type: string + optional: + description: |- + If true, don't block pod startup if the referenced ClusterTrustBundle(s) + aren't available. If using name, then the named ClusterTrustBundle is + allowed not to exist. If using signerName, then the combination of + signerName and labelSelector is allowed to match zero + ClusterTrustBundles. + type: boolean + path: + description: Relative path from the volume root + to write the bundle. + type: string + signerName: + description: |- + Select all ClusterTrustBundles that match this signer name. + Mutually-exclusive with name. The contents of all selected + ClusterTrustBundles will be unified and deduplicated. + type: string + required: + - path + type: object + configMap: + description: configMap information about the configMap + data to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + ConfigMap will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the ConfigMap, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: optional specify whether the ConfigMap + or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information about the downwardAPI + data to project + properties: + items: + description: Items is a list of DownwardAPIVolume + file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema the + FieldPath is written in terms of, + defaults to "v1". + type: string + fieldPath: + description: Path of the field to select + in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: |- + Optional: mode bits used to set permissions on this file, must be an octal value + between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: 'Required: Path is the relative + path name of the file to be created. Must + not be absolute or contain the ''..'' + path. Must be utf-8 encoded. The first + item of the relative path must not start + with ''..''' + type: string + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, requests.cpu and requests.memory) are currently supported. + properties: + containerName: + description: 'Container name: required + for volumes, optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format + of the exposed resources, defaults + to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to + select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about the secret data + to project + properties: + items: + description: |- + items if unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within + a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: optional field specify whether the + Secret or its key must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is information about + the serviceAccountToken data to project + properties: + audience: + description: |- + audience is the intended audience of the token. A recipient of a token + must identify itself with an identifier specified in the audience of the + token, and otherwise should reject the token. The audience defaults to the + identifier of the apiserver. + type: string + expirationSeconds: + description: |- + expirationSeconds is the requested duration of validity of the service + account token. As the token approaches expiration, the kubelet volume + plugin will proactively rotate the service account token. The kubelet will + start trying to rotate the token if the token is older than 80 percent of + its time to live or if the token is older than 24 hours.Defaults to 1 hour + and must be at least 10 minutes. + format: int64 + type: integer + path: + description: |- + path is the path relative to the mount point of the file to project the + token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount on the host + that shares a pod's lifetime + properties: + group: + description: |- + group to map volume access to + Default is no group + type: string + readOnly: + description: |- + readOnly here will force the Quobyte volume to be mounted with read-only permissions. + Defaults to false. + type: boolean + registry: + description: |- + registry represents a single or multiple Quobyte Registry services + specified as a string as host:port pair (multiple entries are separated with commas) + which acts as the central registry for volumes + type: string + tenant: + description: |- + tenant owning the given Quobyte volume in the Backend + Used with dynamically provisioned Quobyte volumes, value is set by the plugin + type: string + user: + description: |- + user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references an already + created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: |- + rbd represents a Rados Block Device mount on the host that shares a pod's lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md + properties: + fsType: + description: |- + fsType is the filesystem type of the volume that you want to mount. + Tip: Ensure that the filesystem type is supported by the host operating system. + Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + More info: https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem from compromising the machine + type: string + image: + description: |- + image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + keyring: + description: |- + keyring is the path to key ring for RBDUser. + Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + monitors: + description: |- + monitors is a collection of Ceph monitors. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + items: + type: string + type: array + pool: + description: |- + pool is the rados pool name. + Default is rbd. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + readOnly: + description: |- + readOnly here will force the ReadOnly setting in VolumeMounts. + Defaults to false. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: boolean + secretRef: + description: |- + secretRef is name of the authentication secret for RBDUser. If provided + overrides keyring. + Default is nil. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: |- + user is the rados user name. + Default is admin. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent volume + attached and mounted on Kubernetes nodes. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". + Default is "xfs". + type: string + gateway: + description: gateway is the host address of the ScaleIO + API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name of the ScaleIO + Protection Domain for the configured storage. + type: string + readOnly: + description: |- + readOnly Defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef references to the secret for ScaleIO user and other + sensitive information. If this is not provided, Login operation will fail. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable SSL communication + with Gateway, default false + type: boolean + storageMode: + description: |- + storageMode indicates whether the storage for a volume should be ThickProvisioned or ThinProvisioned. + Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage Pool associated + with the protection domain. + type: string + system: + description: system is the name of the storage system as + configured in ScaleIO. + type: string + volumeName: + description: |- + volumeName is the name of a volume already created in the ScaleIO system + that is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: |- + secret represents a secret that should populate this volume. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + properties: + defaultMode: + description: |- + defaultMode is Optional: mode bits used to set permissions on created files by default. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values + for mode bits. Defaults to 0644. + Directories within the path are not affected by this setting. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + items: + description: |- + items If unspecified, each key-value pair in the Data field of the referenced + Secret will be projected into the volume as a file whose name is the + key and content is the value. If specified, the listed keys will be + projected into the specified paths, and unlisted keys will not be + present. If a key is specified which is not present in the Secret, + the volume setup will error unless it is marked optional. Paths must be + relative and may not contain the '..' path or start with '..'. + items: + description: Maps a string key to a path within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: |- + mode is Optional: mode bits used to set permissions on this file. + Must be an octal value between 0000 and 0777 or a decimal value between 0 and 511. + YAML accepts both octal and decimal values, JSON requires decimal values for mode bits. + If not specified, the volume defaultMode will be used. + This might be in conflict with other options that affect the file + mode, like fsGroup, and the result can be other mode bits set. + format: int32 + type: integer + path: + description: |- + path is the relative path of the file to map the key to. + May not be an absolute path. + May not contain the path element '..'. + May not start with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether the Secret or + its keys must be defined + type: boolean + secretName: + description: |- + secretName is the name of the secret in the pod's namespace to use. + More info: https://kubernetes.io/docs/concepts/storage/volumes#secret + type: string + type: object + storageos: + description: storageOS represents a StorageOS volume attached + and mounted on Kubernetes nodes. + properties: + fsType: + description: |- + fsType is the filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + readOnly: + description: |- + readOnly defaults to false (read/write). ReadOnly here will force + the ReadOnly setting in VolumeMounts. + type: boolean + secretRef: + description: |- + secretRef specifies the secret to use for obtaining the StorageOS API + credentials. If not specified, default values will be attempted. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: |- + volumeName is the human-readable name of the StorageOS volume. Volume + names are only unique within a namespace. + type: string + volumeNamespace: + description: |- + volumeNamespace specifies the scope of the volume within StorageOS. If no + namespace is specified then the Pod's namespace will be used. This allows the + Kubernetes name scoping to be mirrored within StorageOS for tighter integration. + Set VolumeName to any name to override the default behaviour. + Set to "default" if you are not using namespaces within StorageOS. + Namespaces that do not pre-exist within StorageOS will be created. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere volume attached + and mounted on kubelets host machine + properties: + fsType: + description: |- + fsType is filesystem type to mount. + Must be a filesystem type supported by the host operating system. + Ex. "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage Policy Based + Management (SPBM) profile ID associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage Policy Based + Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies vSphere + volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + web: + description: Defines the web command line flags when starting Alertmanager. + properties: + getConcurrency: + description: |- + Maximum number of GET requests processed concurrently. This corresponds to the + Alertmanager's `--web.get-concurrency` flag. + format: int32 + type: integer + httpConfig: + description: Defines HTTP parameters for web server. + properties: + headers: + description: List of headers that can be added to HTTP responses. + properties: + contentSecurityPolicy: + description: |- + Set the Content-Security-Policy header to HTTP responses. + Unset if blank. + type: string + strictTransportSecurity: + description: |- + Set the Strict-Transport-Security header to HTTP responses. + Unset if blank. + Please make sure that you use this with care as this header might force + browsers to load Prometheus and the other applications hosted on the same + domain and subdomains over HTTPS. + https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security + type: string + xContentTypeOptions: + description: |- + Set the X-Content-Type-Options header to HTTP responses. + Unset if blank. Accepted value is nosniff. + https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options + enum: + - "" + - NoSniff + type: string + xFrameOptions: + description: |- + Set the X-Frame-Options header to HTTP responses. + Unset if blank. Accepted values are deny and sameorigin. + https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options + enum: + - "" + - Deny + - SameOrigin + type: string + xXSSProtection: + description: |- + Set the X-XSS-Protection header to all responses. + Unset if blank. + https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection + type: string + type: object + http2: + description: |- + Enable HTTP/2 support. Note that HTTP/2 is only supported with TLS. + When TLSConfig is not configured, HTTP/2 will be disabled. + Whenever the value of the field changes, a rolling update will be triggered. + type: boolean + type: object + timeout: + description: |- + Timeout for HTTP requests. This corresponds to the Alertmanager's + `--web.timeout` flag. + format: int32 + type: integer + tlsConfig: + description: Defines the TLS parameters for HTTPS. + properties: + cert: + description: Contains the TLS certificate for the server. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cipherSuites: + description: |- + List of supported cipher suites for TLS versions up to TLS 1.2. If empty, + Go default cipher suites are used. Available cipher suites are documented + in the go documentation: https://golang.org/pkg/crypto/tls/#pkg-constants + items: + type: string + type: array + client_ca: + description: Contains the CA certificate for client certificate + authentication to the server. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientAuthType: + description: |- + Server policy for client authentication. Maps to ClientAuth Policies. + For more detail on clientAuth options: + https://golang.org/pkg/crypto/tls/#ClientAuthType + type: string + curvePreferences: + description: |- + Elliptic curves that will be used in an ECDHE handshake, in preference + order. Available curves are documented in the go documentation: + https://golang.org/pkg/crypto/tls/#CurveID + items: + type: string + type: array + keySecret: + description: Secret containing the TLS key for the server. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + maxVersion: + description: Maximum TLS version that is acceptable. Defaults + to TLS13. + type: string + minVersion: + description: Minimum TLS version that is acceptable. Defaults + to TLS12. + type: string + preferServerCipherSuites: + description: |- + Controls whether the server selects the + client's most preferred cipher suite, or the server's most preferred + cipher suite. If true then the server's preference, as expressed in + the order of elements in cipherSuites, is used. + type: boolean + required: + - cert + - keySecret + type: object + type: object + type: object + status: + description: |- + Most recent observed status of the Alertmanager cluster. Read-only. + More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + availableReplicas: + description: |- + Total number of available pods (ready for at least minReadySeconds) + targeted by this Alertmanager cluster. + format: int32 + type: integer + conditions: + description: The current state of the Alertmanager object. + items: + description: |- + Condition represents the state of the resources associated with the + Prometheus, Alertmanager or ThanosRuler resource. + properties: + lastTransitionTime: + description: lastTransitionTime is the time of the last update + to the current status property. + format: date-time + type: string + message: + description: Human-readable message indicating details for the + condition's last transition. + type: string + observedGeneration: + description: |- + ObservedGeneration represents the .metadata.generation that the + condition was set based upon. For instance, if `.metadata.generation` is + currently 12, but the `.status.conditions[].observedGeneration` is 9, the + condition is out of date with respect to the current state of the + instance. + format: int64 + type: integer + reason: + description: Reason for the condition's last transition. + type: string + status: + description: Status of the condition. + type: string + type: + description: Type of the condition being reported. + type: string + required: + - lastTransitionTime + - status + - type + type: object + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + paused: + description: |- + Represents whether any actions on the underlying managed objects are + being performed. Only delete actions will be performed. + type: boolean + replicas: + description: |- + Total number of non-terminated pods targeted by this Alertmanager + object (their labels match the selector). + format: int32 + type: integer + unavailableReplicas: + description: Total number of unavailable pods targeted by this Alertmanager + object. + format: int32 + type: integer + updatedReplicas: + description: |- + Total number of non-terminated pods targeted by this Alertmanager + object that have the desired version spec. + format: int32 + type: integer + required: + - availableReplicas + - paused + - replicas + - unavailableReplicas + - updatedReplicas + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-podmonitors.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-podmonitors.yaml new file mode 100644 index 000000000..1db48b269 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-podmonitors.yaml @@ -0,0 +1,905 @@ +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_podmonitors.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + operator.prometheus.io/version: 0.74.0 + name: podmonitors.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: PodMonitor + listKind: PodMonitorList + plural: podmonitors + shortNames: + - pmon + singular: podmonitor + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: PodMonitor defines monitoring for a set of pods. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of desired Pod selection for target discovery + by Prometheus. + properties: + attachMetadata: + description: |- + `attachMetadata` defines additional metadata which is added to the + discovered targets. + + + It requires Prometheus >= v2.37.0. + properties: + node: + description: |- + When set to true, Prometheus must have the `get` permission on the + `Nodes` objects. + type: boolean + type: object + bodySizeLimit: + description: |- + When defined, bodySizeLimit specifies a job level limit on the size + of uncompressed response body that will be accepted by Prometheus. + + + It requires Prometheus >= v2.28.0. + pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ + type: string + jobLabel: + description: |- + The label to use to retrieve the job name from. + `jobLabel` selects the label from the associated Kubernetes `Pod` + object which will be used as the `job` label for all metrics. + + + For example if `jobLabel` is set to `foo` and the Kubernetes `Pod` + object is labeled with `foo: bar`, then Prometheus adds the `job="bar"` + label to all ingested metrics. + + + If the value of this field is empty, the `job` label of the metrics + defaults to the namespace and name of the PodMonitor object (e.g. `/`). + type: string + keepDroppedTargets: + description: |- + Per-scrape limit on the number of targets dropped by relabeling + that will be kept in memory. 0 means no limit. + + + It requires Prometheus >= v2.47.0. + format: int64 + type: integer + labelLimit: + description: |- + Per-scrape limit on number of labels that will be accepted for a sample. + + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + labelNameLengthLimit: + description: |- + Per-scrape limit on length of labels name that will be accepted for a sample. + + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + labelValueLengthLimit: + description: |- + Per-scrape limit on length of labels value that will be accepted for a sample. + + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + namespaceSelector: + description: |- + Selector to select which namespaces the Kubernetes `Pods` objects + are discovered from. + properties: + any: + description: |- + Boolean describing whether all namespaces are selected in contrast to a + list restricting them. + type: boolean + matchNames: + description: List of namespace names to select from. + items: + type: string + type: array + type: object + podMetricsEndpoints: + description: List of endpoints part of this PodMonitor. + items: + description: |- + PodMetricsEndpoint defines an endpoint serving Prometheus metrics to be scraped by + Prometheus. + properties: + authorization: + description: |- + `authorization` configures the Authorization header credentials to use when + scraping the target. + + + Cannot be set at the same time as `basicAuth`, or `oauth2`. + properties: + credentials: + description: Selects a key of a Secret in the namespace + that contains the credentials for authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + `basicAuth` configures the Basic Authentication credentials to use when + scraping the target. + + + Cannot be set at the same time as `authorization`, or `oauth2`. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + `bearerTokenSecret` specifies a key of a Secret containing the bearer + token for scraping targets. The secret needs to be in the same namespace + as the PodMonitor object and readable by the Prometheus Operator. + + + Deprecated: use `authorization` instead. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + enableHttp2: + description: '`enableHttp2` can be used to disable HTTP2 when + scraping the target.' + type: boolean + filterRunning: + description: |- + When true, the pods which are not running (e.g. either in Failed or + Succeeded state) are dropped during the target discovery. + + + If unset, the filtering is enabled. + + + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#pod-phase + type: boolean + followRedirects: + description: |- + `followRedirects` defines whether the scrape requests should follow HTTP + 3xx redirects. + type: boolean + honorLabels: + description: |- + When true, `honorLabels` preserves the metric's labels when they collide + with the target's labels. + type: boolean + honorTimestamps: + description: |- + `honorTimestamps` controls whether Prometheus preserves the timestamps + when exposed by the target. + type: boolean + interval: + description: |- + Interval at which Prometheus scrapes the metrics from the target. + + + If empty, Prometheus uses the global scrape interval. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + metricRelabelings: + description: |- + `metricRelabelings` configures the relabeling rules to apply to the + samples before ingestion. + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + Action to perform based on the regex matching. + + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + Modulus to take of the hash of the source label values. + + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: Regular expression against which the extracted + value is matched. + type: string + replacement: + description: |- + Replacement value against which a Replace action is performed if the + regular expression matches. + + + Regex capture groups are available. + type: string + separator: + description: Separator is the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + The source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: |- + Label to which the resulting string is written in a replacement. + + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + + Regex capture groups are available. + type: string + type: object + type: array + oauth2: + description: |- + `oauth2` configures the OAuth2 settings to use when scraping the target. + + + It requires Prometheus >= 2.27.0. + + + Cannot be set at the same time as `authorization`, or `basicAuth`. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes used for + the token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to fetch the + token from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + params: + additionalProperties: + items: + type: string + type: array + description: '`params` define optional HTTP URL parameters.' + type: object + path: + description: |- + HTTP path from which to scrape for metrics. + + + If empty, Prometheus uses the default value (e.g. `/metrics`). + type: string + port: + description: |- + Name of the Pod port which this endpoint refers to. + + + It takes precedence over `targetPort`. + type: string + proxyUrl: + description: |- + `proxyURL` configures the HTTP Proxy URL (e.g. + "http://proxyserver:2195") to go through when scraping the target. + type: string + relabelings: + description: |- + `relabelings` configures the relabeling rules to apply the target's + metadata labels. + + + The Operator automatically adds relabelings for a few standard Kubernetes fields. + + + The original scrape job's name is available via the `__tmp_prometheus_job_name` label. + + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + Action to perform based on the regex matching. + + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + Modulus to take of the hash of the source label values. + + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: Regular expression against which the extracted + value is matched. + type: string + replacement: + description: |- + Replacement value against which a Replace action is performed if the + regular expression matches. + + + Regex capture groups are available. + type: string + separator: + description: Separator is the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + The source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: |- + Label to which the resulting string is written in a replacement. + + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + + Regex capture groups are available. + type: string + type: object + type: array + scheme: + description: |- + HTTP scheme to use for scraping. + + + `http` and `https` are the expected values unless you rewrite the + `__scheme__` label via relabeling. + + + If empty, Prometheus uses the default value `http`. + enum: + - http + - https + type: string + scrapeTimeout: + description: |- + Timeout after which Prometheus considers the scrape to be failed. + + + If empty, Prometheus uses the global scrape timeout unless it is less + than the target's scrape interval value in which the latter is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + targetPort: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the target port of the `Pod` object behind the Service, the + port must be specified with container port property. + + + Deprecated: use 'port' instead. + x-kubernetes-int-or-string: true + tlsConfig: + description: TLS configuration to use when scraping the target. + properties: + ca: + description: Certificate authority used when verifying server + certificates. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key file for the + targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the targets. + type: string + type: object + trackTimestampsStaleness: + description: |- + `trackTimestampsStaleness` defines whether Prometheus tracks staleness of + the metrics that have an explicit timestamp present in scraped data. + Has no effect if `honorTimestamps` is false. + + + It requires Prometheus >= v2.48.0. + type: boolean + type: object + type: array + podTargetLabels: + description: |- + `podTargetLabels` defines the labels which are transferred from the + associated Kubernetes `Pod` object onto the ingested metrics. + items: + type: string + type: array + sampleLimit: + description: |- + `sampleLimit` defines a per-scrape limit on the number of scraped samples + that will be accepted. + format: int64 + type: integer + scrapeClass: + description: The scrape class to apply. + minLength: 1 + type: string + scrapeProtocols: + description: |- + `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + protocols supported by Prometheus in order of preference (from most to least preferred). + + + If unset, Prometheus uses its default value. + + + It requires Prometheus >= v2.49.0. + items: + description: |- + ScrapeProtocol represents a protocol used by Prometheus for scraping metrics. + Supported values are: + * `OpenMetricsText0.0.1` + * `OpenMetricsText1.0.0` + * `PrometheusProto` + * `PrometheusText0.0.4` + enum: + - PrometheusProto + - OpenMetricsText0.0.1 + - OpenMetricsText1.0.0 + - PrometheusText0.0.4 + type: string + type: array + x-kubernetes-list-type: set + selector: + description: Label selector to select the Kubernetes `Pod` objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector requirements. + The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector applies + to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + targetLimit: + description: |- + `targetLimit` defines a limit on the number of scraped targets that will + be accepted. + format: int64 + type: integer + required: + - selector + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-probes.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-probes.yaml new file mode 100644 index 000000000..e65f976c1 --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-probes.yaml @@ -0,0 +1,881 @@ +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_probes.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + operator.prometheus.io/version: 0.74.0 + name: probes.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: Probe + listKind: ProbeList + plural: probes + shortNames: + - prb + singular: probe + scope: Namespaced + versions: + - name: v1 + schema: + openAPIV3Schema: + description: Probe defines monitoring for a set of static targets or ingresses. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Specification of desired Ingress selection for target discovery + by Prometheus. + properties: + authorization: + description: Authorization section for this endpoint + properties: + credentials: + description: Selects a key of a Secret in the namespace that contains + the credentials for authentication. + properties: + key: + description: The key of the secret to select from. Must be + a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth allow an endpoint to authenticate over basic authentication. + More info: https://prometheus.io/docs/operating/configuration/#endpoint + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select from. Must be + a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select from. Must be + a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerTokenSecret: + description: |- + Secret to mount to read bearer token for scraping targets. The secret + needs to be in the same namespace as the probe and accessible by + the Prometheus Operator. + properties: + key: + description: The key of the secret to select from. Must be a + valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + interval: + description: |- + Interval at which targets are probed using the configured prober. + If not specified Prometheus' global scrape interval is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + jobName: + description: The job name assigned to scraped metrics by default. + type: string + keepDroppedTargets: + description: |- + Per-scrape limit on the number of targets dropped by relabeling + that will be kept in memory. 0 means no limit. + + + It requires Prometheus >= v2.47.0. + format: int64 + type: integer + labelLimit: + description: |- + Per-scrape limit on number of labels that will be accepted for a sample. + Only valid in Prometheus versions 2.27.0 and newer. + format: int64 + type: integer + labelNameLengthLimit: + description: |- + Per-scrape limit on length of labels name that will be accepted for a sample. + Only valid in Prometheus versions 2.27.0 and newer. + format: int64 + type: integer + labelValueLengthLimit: + description: |- + Per-scrape limit on length of labels value that will be accepted for a sample. + Only valid in Prometheus versions 2.27.0 and newer. + format: int64 + type: integer + metricRelabelings: + description: MetricRelabelConfigs to apply to samples before ingestion. + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + Action to perform based on the regex matching. + + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + Modulus to take of the hash of the source label values. + + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: Regular expression against which the extracted + value is matched. + type: string + replacement: + description: |- + Replacement value against which a Replace action is performed if the + regular expression matches. + + + Regex capture groups are available. + type: string + separator: + description: Separator is the string between concatenated SourceLabels. + type: string + sourceLabels: + description: |- + The source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: |- + Label to which the resulting string is written in a replacement. + + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + + Regex capture groups are available. + type: string + type: object + type: array + module: + description: |- + The module to use for probing specifying how to probe the target. + Example module configuring in the blackbox exporter: + https://github.com/prometheus/blackbox_exporter/blob/master/example.yml + type: string + oauth2: + description: OAuth2 for the URL. Only valid in Prometheus versions + 2.27.0 and newer. + properties: + clientId: + description: |- + `clientId` specifies a key of a Secret or ConfigMap containing the + OAuth2 client's ID. + properties: + configMap: + description: ConfigMap containing data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + clientSecret: + description: |- + `clientSecret` specifies a key of a Secret containing the OAuth2 + client's secret. + properties: + key: + description: The key of the secret to select from. Must be + a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + endpointParams: + additionalProperties: + type: string + description: |- + `endpointParams` configures the HTTP parameters to append to the token + URL. + type: object + scopes: + description: '`scopes` defines the OAuth2 scopes used for the + token request.' + items: + type: string + type: array + tokenUrl: + description: '`tokenURL` configures the URL to fetch the token + from.' + minLength: 1 + type: string + required: + - clientId + - clientSecret + - tokenUrl + type: object + prober: + description: |- + Specification for the prober to use for probing targets. + The prober.URL parameter is required. Targets cannot be probed if left empty. + properties: + path: + default: /probe + description: |- + Path to collect metrics from. + Defaults to `/probe`. + type: string + proxyUrl: + description: Optional ProxyURL. + type: string + scheme: + description: |- + HTTP scheme to use for scraping. + `http` and `https` are the expected values unless you rewrite the `__scheme__` label via relabeling. + If empty, Prometheus uses the default value `http`. + enum: + - http + - https + type: string + url: + description: Mandatory URL of the prober. + type: string + required: + - url + type: object + sampleLimit: + description: SampleLimit defines per-scrape limit on number of scraped + samples that will be accepted. + format: int64 + type: integer + scrapeClass: + description: The scrape class to apply. + minLength: 1 + type: string + scrapeProtocols: + description: |- + `scrapeProtocols` defines the protocols to negotiate during a scrape. It tells clients the + protocols supported by Prometheus in order of preference (from most to least preferred). + + + If unset, Prometheus uses its default value. + + + It requires Prometheus >= v2.49.0. + items: + description: |- + ScrapeProtocol represents a protocol used by Prometheus for scraping metrics. + Supported values are: + * `OpenMetricsText0.0.1` + * `OpenMetricsText1.0.0` + * `PrometheusProto` + * `PrometheusText0.0.4` + enum: + - PrometheusProto + - OpenMetricsText0.0.1 + - OpenMetricsText1.0.0 + - PrometheusText0.0.4 + type: string + type: array + x-kubernetes-list-type: set + scrapeTimeout: + description: |- + Timeout for scraping metrics from the Prometheus exporter. + If not specified, the Prometheus global scrape timeout is used. + pattern: ^(0|(([0-9]+)y)?(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?(([0-9]+)ms)?)$ + type: string + targetLimit: + description: TargetLimit defines a limit on the number of scraped + targets that will be accepted. + format: int64 + type: integer + targets: + description: Targets defines a set of static or dynamically discovered + targets to probe. + properties: + ingress: + description: |- + ingress defines the Ingress objects to probe and the relabeling + configuration. + If `staticConfig` is also defined, `staticConfig` takes precedence. + properties: + namespaceSelector: + description: From which namespaces to select Ingress objects. + properties: + any: + description: |- + Boolean describing whether all namespaces are selected in contrast to a + list restricting them. + type: boolean + matchNames: + description: List of namespace names to select from. + items: + type: string + type: array + type: object + relabelingConfigs: + description: |- + RelabelConfigs to apply to the label set of the target before it gets + scraped. + The original ingress address is available via the + `__tmp_prometheus_ingress_address` label. It can be used to customize the + probed URL. + The original scrape job's name is available via the `__tmp_prometheus_job_name` label. + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + Action to perform based on the regex matching. + + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + Modulus to take of the hash of the source label values. + + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: Regular expression against which the extracted + value is matched. + type: string + replacement: + description: |- + Replacement value against which a Replace action is performed if the + regular expression matches. + + + Regex capture groups are available. + type: string + separator: + description: Separator is the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + The source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: |- + Label to which the resulting string is written in a replacement. + + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + + Regex capture groups are available. + type: string + type: object + type: array + selector: + description: Selector to select the Ingress objects. + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + type: object + staticConfig: + description: |- + staticConfig defines the static list of targets to probe and the + relabeling configuration. + If `ingress` is also defined, `staticConfig` takes precedence. + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#static_config. + properties: + labels: + additionalProperties: + type: string + description: Labels assigned to all metrics scraped from the + targets. + type: object + relabelingConfigs: + description: |- + RelabelConfigs to apply to the label set of the targets before it gets + scraped. + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + items: + description: |- + RelabelConfig allows dynamic rewriting of the label set for targets, alerts, + scraped samples and remote write samples. + + + More info: https://prometheus.io/docs/prometheus/latest/configuration/configuration/#relabel_config + properties: + action: + default: replace + description: |- + Action to perform based on the regex matching. + + + `Uppercase` and `Lowercase` actions require Prometheus >= v2.36.0. + `DropEqual` and `KeepEqual` actions require Prometheus >= v2.41.0. + + + Default: "Replace" + enum: + - replace + - Replace + - keep + - Keep + - drop + - Drop + - hashmod + - HashMod + - labelmap + - LabelMap + - labeldrop + - LabelDrop + - labelkeep + - LabelKeep + - lowercase + - Lowercase + - uppercase + - Uppercase + - keepequal + - KeepEqual + - dropequal + - DropEqual + type: string + modulus: + description: |- + Modulus to take of the hash of the source label values. + + + Only applicable when the action is `HashMod`. + format: int64 + type: integer + regex: + description: Regular expression against which the extracted + value is matched. + type: string + replacement: + description: |- + Replacement value against which a Replace action is performed if the + regular expression matches. + + + Regex capture groups are available. + type: string + separator: + description: Separator is the string between concatenated + SourceLabels. + type: string + sourceLabels: + description: |- + The source labels select values from existing labels. Their content is + concatenated using the configured Separator and matched against the + configured regular expression. + items: + description: |- + LabelName is a valid Prometheus label name which may only contain ASCII + letters, numbers, as well as underscores. + pattern: ^[a-zA-Z_][a-zA-Z0-9_]*$ + type: string + type: array + targetLabel: + description: |- + Label to which the resulting string is written in a replacement. + + + It is mandatory for `Replace`, `HashMod`, `Lowercase`, `Uppercase`, + `KeepEqual` and `DropEqual` actions. + + + Regex capture groups are available. + type: string + type: object + type: array + static: + description: The list of hosts to probe. + items: + type: string + type: array + type: object + type: object + tlsConfig: + description: TLS configuration to use when scraping the endpoint. + properties: + ca: + description: Certificate authority used when verifying server + certificates. + properties: + configMap: + description: ConfigMap containing data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + cert: + description: Client certificate to present when doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to use for the targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keySecret: + description: Secret containing the client key file for the targets. + properties: + key: + description: The key of the secret to select from. Must be + a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be + defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the targets. + type: string + type: object + type: object + required: + - spec + type: object + served: true + storage: true diff --git a/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-prometheusagents.yaml b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-prometheusagents.yaml new file mode 100644 index 000000000..caa24793b --- /dev/null +++ b/backend/charts/deepgram-self-hosted/nova-3/charts/kube-prometheus-stack/charts/crds/crds/crd-prometheusagents.yaml @@ -0,0 +1,9525 @@ +# https://raw.githubusercontent.com/prometheus-operator/prometheus-operator/v0.74.0/example/prometheus-operator-crd/monitoring.coreos.com_prometheusagents.yaml +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.14.0 + operator.prometheus.io/version: 0.74.0 + name: prometheusagents.monitoring.coreos.com +spec: + group: monitoring.coreos.com + names: + categories: + - prometheus-operator + kind: PrometheusAgent + listKind: PrometheusAgentList + plural: prometheusagents + shortNames: + - promagent + singular: prometheusagent + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: The version of Prometheus agent + jsonPath: .spec.version + name: Version + type: string + - description: The number of desired replicas + jsonPath: .spec.replicas + name: Desired + type: integer + - description: The number of ready replicas + jsonPath: .status.availableReplicas + name: Ready + type: integer + - jsonPath: .status.conditions[?(@.type == 'Reconciled')].status + name: Reconciled + type: string + - jsonPath: .status.conditions[?(@.type == 'Available')].status + name: Available + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - description: Whether the resource reconciliation is paused or not + jsonPath: .status.paused + name: Paused + priority: 1 + type: boolean + name: v1alpha1 + schema: + openAPIV3Schema: + description: PrometheusAgent defines a Prometheus agent deployment. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: |- + Specification of the desired behavior of the Prometheus agent. More info: + https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status + properties: + additionalArgs: + description: |- + AdditionalArgs allows setting additional arguments for the 'prometheus' container. + + + It is intended for e.g. activating hidden flags which are not supported by + the dedicated configuration options yet. The arguments are passed as-is to the + Prometheus container which may cause issues if they are invalid or not supported + by the given Prometheus version. + + + In case of an argument conflict (e.g. an argument which is already set by the + operator itself) or when providing an invalid argument, the reconciliation will + fail and an error will be logged. + items: + description: Argument as part of the AdditionalArgs list. + properties: + name: + description: Name of the argument, e.g. "scrape.discovery-reload-interval". + minLength: 1 + type: string + value: + description: Argument value, e.g. 30s. Can be empty for name-only + arguments (e.g. --storage.tsdb.no-lockfile) + type: string + required: + - name + type: object + type: array + additionalScrapeConfigs: + description: |- + AdditionalScrapeConfigs allows specifying a key of a Secret containing + additional Prometheus scrape configurations. Scrape configurations + specified are appended to the configurations generated by the Prometheus + Operator. Job configurations specified must have the form as specified + in the official Prometheus documentation: + https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config. + As scrape configs are appended, the user is responsible to make sure it + is valid. Note that using this feature may expose the possibility to + break upgrades of Prometheus. It is advised to review Prometheus release + notes to ensure that no incompatible scrape configs are going to break + Prometheus after the upgrade. + properties: + key: + description: The key of the secret to select from. Must be a + valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + affinity: + description: Defines the Pods' affinity scheduling rules if specified. + properties: + nodeAffinity: + description: Describes node affinity scheduling rules for the + pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node matches the corresponding matchExpressions; the + node(s) with the highest sum are the most preferred. + items: + description: |- + An empty preferred scheduling term matches all objects with implicit weight 0 + (i.e. it's a no-op). A null preferred scheduling term matches no objects (i.e. is also a no-op). + properties: + preference: + description: A node selector term, associated with the + corresponding weight. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching the corresponding + nodeSelectorTerm, in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to an update), the system + may or may not try to eventually evict the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector terms. + The terms are ORed. + items: + description: |- + A null or empty node selector term matches no objects. The requirements of + them are ANDed. + The TopologySelectorTerm type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector requirements + by node's labels. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector requirements + by node's fields. + items: + description: |- + A node selector requirement is a selector that contains values, a key, and an operator + that relates the key and values. + properties: + key: + description: The label key that the selector + applies to. + type: string + operator: + description: |- + Represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists, DoesNotExist. Gt, and Lt. + type: string + values: + description: |- + An array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. If the operator is Gt or Lt, the values + array must have a single element, which will be interpreted as an integer. + This array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules (e.g. co-locate + this pod in the same node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling rules (e.g. + avoid putting this pod in the same node, zone, etc. as some + other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: |- + The scheduler will prefer to schedule pods to nodes that satisfy + the anti-affinity expressions specified by this field, but it may choose + a node that violates one or more of the expressions. The node that is + most preferred is the one with the greatest sum of weights, i.e. + for each node that meets all of the scheduling requirements (resource + request, requiredDuringScheduling anti-affinity expressions, etc.), + compute a sum by iterating through the elements of this field and adding + "weight" to the sum if the node has pods which matches the corresponding podAffinityTerm; the + node(s) with the highest sum are the most preferred. + items: + description: The weights of all of the matched WeightedPodAffinityTerm + fields are added per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity term, associated + with the corresponding weight. + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are + ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: |- + weight associated with matching the corresponding podAffinityTerm, + in the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: |- + If the anti-affinity requirements specified by this field are not met at + scheduling time, the pod will not be scheduled onto the node. + If the anti-affinity requirements specified by this field cease to be met + at some point during pod execution (e.g. due to a pod label update), the + system may or may not try to eventually evict the pod from its node. + When there are multiple elements, the lists of nodes corresponding to each + podAffinityTerm are intersected, i.e. all terms must be satisfied. + items: + description: |- + Defines a set of pods (namely those matching the labelSelector + relative to the given namespace(s)) that this pod should be + co-located (affinity) or not co-located (anti-affinity) with, + where co-located is defined as running on a node whose value of + the label with key matches that of any node on which + a pod of the set of pods is running + properties: + labelSelector: + description: |- + A label query over a set of resources, in this case pods. + If it's null, this PodAffinityTerm matches with no Pods. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: |- + MatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key in (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MatchLabelKeys and LabelSelector. + Also, MatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + mismatchLabelKeys: + description: |- + MismatchLabelKeys is a set of pod label keys to select which pods will + be taken into consideration. The keys are used to lookup values from the + incoming pod labels, those key-value labels are merged with `LabelSelector` as `key notin (value)` + to select the group of existing pods which pods will be taken into consideration + for the incoming pod's pod (anti) affinity. Keys that don't exist in the incoming + pod labels will be ignored. The default value is empty. + The same key is forbidden to exist in both MismatchLabelKeys and LabelSelector. + Also, MismatchLabelKeys cannot be set when LabelSelector isn't set. + This is an alpha field and requires enabling MatchLabelKeysInPodAffinity feature gate. + items: + type: string + type: array + x-kubernetes-list-type: atomic + namespaceSelector: + description: |- + A label query over the set of namespaces that the term applies to. + The term is applied to the union of the namespaces selected by this field + and the ones listed in the namespaces field. + null selector and null or empty namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a list of label + selector requirements. The requirements are ANDed. + items: + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. + properties: + key: + description: key is the label key that the + selector applies to. + type: string + operator: + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. + type: string + values: + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: |- + namespaces specifies a static list of namespace names that the term applies to. + The term is applied to the union of the namespaces listed in this field + and the ones selected by namespaceSelector. + null or empty namespaces list and null namespaceSelector means "this pod's namespace". + items: + type: string + type: array + topologyKey: + description: |- + This pod should be co-located (affinity) or not co-located (anti-affinity) with the pods matching + the labelSelector in the specified namespaces, where co-located is defined as running on a node + whose value of the label with key topologyKey matches that of any node on which any of the + selected pods is running. + Empty topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + apiserverConfig: + description: |- + APIServerConfig allows specifying a host and auth methods to access the + Kuberntees API server. + If null, Prometheus is assumed to run inside of the cluster: it will + discover the API servers automatically and use the Pod's CA certificate + and bearer token file at /var/run/secrets/kubernetes.io/serviceaccount/. + properties: + authorization: + description: |- + Authorization section for the API server. + + + Cannot be set at the same time as `basicAuth`, `bearerToken`, or + `bearerTokenFile`. + properties: + credentials: + description: Selects a key of a Secret in the namespace that + contains the credentials for authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + credentialsFile: + description: File to read a secret from, mutually exclusive + with `credentials`. + type: string + type: + description: |- + Defines the authentication type. The value is case-insensitive. + + + "Basic" is not a supported value. + + + Default: "Bearer" + type: string + type: object + basicAuth: + description: |- + BasicAuth configuration for the API server. + + + Cannot be set at the same time as `authorization`, `bearerToken`, or + `bearerTokenFile`. + properties: + password: + description: |- + `password` specifies a key of a Secret containing the password for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + username: + description: |- + `username` specifies a key of a Secret containing the username for + authentication. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + bearerToken: + description: |- + *Warning: this field shouldn't be used because the token value appears + in clear-text. Prefer using `authorization`.* + + + Deprecated: this will be removed in a future release. + type: string + bearerTokenFile: + description: |- + File to read bearer token for accessing apiserver. + + + Cannot be set at the same time as `basicAuth`, `authorization`, or `bearerToken`. + + + Deprecated: this will be removed in a future release. Prefer using `authorization`. + type: string + host: + description: |- + Kubernetes API address consisting of a hostname or IP address followed + by an optional port number. + type: string + tlsConfig: + description: TLS Config to use for the API server. + properties: + ca: + description: Certificate authority used when verifying server + certificates. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + caFile: + description: Path to the CA cert in the Prometheus container + to use for the targets. + type: string + cert: + description: Client certificate to present when doing client-authentication. + properties: + configMap: + description: ConfigMap containing data to use for the + targets. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + secret: + description: Secret containing data to use for the targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key + must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + certFile: + description: Path to the client cert file in the Prometheus + container for the targets. + type: string + insecureSkipVerify: + description: Disable target certificate validation. + type: boolean + keyFile: + description: Path to the client key file in the Prometheus + container for the targets. + type: string + keySecret: + description: Secret containing the client key file for the + targets. + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its key must + be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + serverName: + description: Used to verify the hostname for the targets. + type: string + type: object + required: + - host + type: object + arbitraryFSAccessThroughSMs: + description: |- + When true, ServiceMonitor, PodMonitor and Probe object are forbidden to + reference arbitrary files on the file system of the 'prometheus' + container. + When a ServiceMonitor's endpoint specifies a `bearerTokenFile` value + (e.g. '/var/run/secrets/kubernetes.io/serviceaccount/token'), a + malicious target can get access to the Prometheus service account's + token in the Prometheus' scrape request. Setting + `spec.arbitraryFSAccessThroughSM` to 'true' would prevent the attack. + Users should instead provide the credentials using the + `spec.bearerTokenSecret` field. + properties: + deny: + type: boolean + type: object + automountServiceAccountToken: + description: |- + AutomountServiceAccountToken indicates whether a service account token should be automatically mounted in the pod. + If the field isn't set, the operator mounts the service account token by default. + + + **Warning:** be aware that by default, Prometheus requires the service account token for Kubernetes service discovery. + It is possible to use strategic merge patch to project the service account token into the 'prometheus' container. + type: boolean + bodySizeLimit: + description: |- + BodySizeLimit defines per-scrape on response body size. + Only valid in Prometheus versions 2.45.0 and newer. + pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ + type: string + configMaps: + description: |- + ConfigMaps is a list of ConfigMaps in the same namespace as the Prometheus + object, which shall be mounted into the Prometheus Pods. + Each ConfigMap is added to the StatefulSet definition as a volume named `configmap-`. + The ConfigMaps are mounted into /etc/prometheus/configmaps/ in the 'prometheus' container. + items: + type: string + type: array + containers: + description: |- + Containers allows injecting additional containers or modifying operator + generated containers. This can be used to allow adding an authentication + proxy to the Pods or to change the behavior of an operator generated + container. Containers described here modify an operator generated + container if they share the same name and modifications are done via a + strategic merge patch. + + + The names of containers managed by the operator are: + * `prometheus` + * `config-reloader` + * `thanos-sidecar` + + + Overriding containers is entirely outside the scope of what the + maintainers will support and by doing so, you accept that this behaviour + may break at any time without notice. + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This field may only be set for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Setting the RestartPolicy as "Always" for the init container will have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default is DefaultProcMount which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + enableFeatures: + description: |- + Enable access to Prometheus feature flags. By default, no features are enabled. + + + Enabling features which are disabled by default is entirely outside the + scope of what the maintainers will support and by doing so, you accept + that this behaviour may break at any time without notice. + + + For more information see https://prometheus.io/docs/prometheus/latest/feature_flags/ + items: + minLength: 1 + type: string + type: array + x-kubernetes-list-type: set + enableRemoteWriteReceiver: + description: |- + Enable Prometheus to be used as a receiver for the Prometheus remote + write protocol. + + + WARNING: This is not considered an efficient way of ingesting samples. + Use it with caution for specific low-volume use cases. + It is not suitable for replacing the ingestion via scraping and turning + Prometheus into a push-based metrics collection system. + For more information see https://prometheus.io/docs/prometheus/latest/querying/api/#remote-write-receiver + + + It requires Prometheus >= v2.33.0. + type: boolean + enforcedBodySizeLimit: + description: |- + When defined, enforcedBodySizeLimit specifies a global limit on the size + of uncompressed response body that will be accepted by Prometheus. + Targets responding with a body larger than this many bytes will cause + the scrape to fail. + + + It requires Prometheus >= v2.28.0. + pattern: (^0|([0-9]*[.])?[0-9]+((K|M|G|T|E|P)i?)?B)$ + type: string + enforcedKeepDroppedTargets: + description: |- + When defined, enforcedKeepDroppedTargets specifies a global limit on the number of targets + dropped by relabeling that will be kept in memory. The value overrides + any `spec.keepDroppedTargets` set by + ServiceMonitor, PodMonitor, Probe objects unless `spec.keepDroppedTargets` is + greater than zero and less than `spec.enforcedKeepDroppedTargets`. + + + It requires Prometheus >= v2.47.0. + format: int64 + type: integer + enforcedLabelLimit: + description: |- + When defined, enforcedLabelLimit specifies a global limit on the number + of labels per sample. The value overrides any `spec.labelLimit` set by + ServiceMonitor, PodMonitor, Probe objects unless `spec.labelLimit` is + greater than zero and less than `spec.enforcedLabelLimit`. + + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + enforcedLabelNameLengthLimit: + description: |- + When defined, enforcedLabelNameLengthLimit specifies a global limit on the length + of labels name per sample. The value overrides any `spec.labelNameLengthLimit` set by + ServiceMonitor, PodMonitor, Probe objects unless `spec.labelNameLengthLimit` is + greater than zero and less than `spec.enforcedLabelNameLengthLimit`. + + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + enforcedLabelValueLengthLimit: + description: |- + When not null, enforcedLabelValueLengthLimit defines a global limit on the length + of labels value per sample. The value overrides any `spec.labelValueLengthLimit` set by + ServiceMonitor, PodMonitor, Probe objects unless `spec.labelValueLengthLimit` is + greater than zero and less than `spec.enforcedLabelValueLengthLimit`. + + + It requires Prometheus >= v2.27.0. + format: int64 + type: integer + enforcedNamespaceLabel: + description: |- + When not empty, a label will be added to: + + + 1. All metrics scraped from `ServiceMonitor`, `PodMonitor`, `Probe` and `ScrapeConfig` objects. + 2. All metrics generated from recording rules defined in `PrometheusRule` objects. + 3. All alerts generated from alerting rules defined in `PrometheusRule` objects. + 4. All vector selectors of PromQL expressions defined in `PrometheusRule` objects. + + + The label will not added for objects referenced in `spec.excludedFromEnforcement`. + + + The label's name is this field's value. + The label's value is the namespace of the `ServiceMonitor`, + `PodMonitor`, `Probe`, `PrometheusRule` or `ScrapeConfig` object. + type: string + enforcedSampleLimit: + description: |- + When defined, enforcedSampleLimit specifies a global limit on the number + of scraped samples that will be accepted. This overrides any + `spec.sampleLimit` set by ServiceMonitor, PodMonitor, Probe objects + unless `spec.sampleLimit` is greater than zero and less than + `spec.enforcedSampleLimit`. + + + It is meant to be used by admins to keep the overall number of + samples/series under a desired limit. + format: int64 + type: integer + enforcedTargetLimit: + description: |- + When defined, enforcedTargetLimit specifies a global limit on the number + of scraped targets. The value overrides any `spec.targetLimit` set by + ServiceMonitor, PodMonitor, Probe objects unless `spec.targetLimit` is + greater than zero and less than `spec.enforcedTargetLimit`. + + + It is meant to be used by admins to to keep the overall number of + targets under a desired limit. + format: int64 + type: integer + excludedFromEnforcement: + description: |- + List of references to PodMonitor, ServiceMonitor, Probe and PrometheusRule objects + to be excluded from enforcing a namespace label of origin. + + + It is only applicable if `spec.enforcedNamespaceLabel` set to true. + items: + description: ObjectReference references a PodMonitor, ServiceMonitor, + Probe or PrometheusRule object. + properties: + group: + default: monitoring.coreos.com + description: Group of the referent. When not specified, it defaults + to `monitoring.coreos.com` + enum: + - monitoring.coreos.com + type: string + name: + description: Name of the referent. When not set, all resources + in the namespace are matched. + type: string + namespace: + description: |- + Namespace of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ + minLength: 1 + type: string + resource: + description: Resource of the referent. + enum: + - prometheusrules + - servicemonitors + - podmonitors + - probes + - scrapeconfigs + type: string + required: + - namespace + - resource + type: object + type: array + externalLabels: + additionalProperties: + type: string + description: |- + The labels to add to any time series or alerts when communicating with + external systems (federation, remote storage, Alertmanager). + Labels defined by `spec.replicaExternalLabelName` and + `spec.prometheusExternalLabelName` take precedence over this list. + type: object + externalUrl: + description: |- + The external URL under which the Prometheus service is externally + available. This is necessary to generate correct URLs (for instance if + Prometheus is accessible behind an Ingress resource). + type: string + hostAliases: + description: |- + Optional list of hosts and IPs that will be injected into the Pod's + hosts file if specified. + items: + description: |- + HostAlias holds the mapping between IP and hostnames that will be injected as an entry in the + pod's hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + ip: + description: IP address of the host file entry. + type: string + required: + - hostnames + - ip + type: object + type: array + x-kubernetes-list-map-keys: + - ip + x-kubernetes-list-type: map + hostNetwork: + description: |- + Use the host's network namespace if true. + + + Make sure to understand the security implications if you want to enable + it (https://kubernetes.io/docs/concepts/configuration/overview/). + + + When hostNetwork is enabled, this will set the DNS policy to + `ClusterFirstWithHostNet` automatically. + type: boolean + ignoreNamespaceSelectors: + description: |- + When true, `spec.namespaceSelector` from all PodMonitor, ServiceMonitor + and Probe objects will be ignored. They will only discover targets + within the namespace of the PodMonitor, ServiceMonitor and Probe + object. + type: boolean + image: + description: |- + Container image name for Prometheus. If specified, it takes precedence + over the `spec.baseImage`, `spec.tag` and `spec.sha` fields. + + + Specifying `spec.version` is still necessary to ensure the Prometheus + Operator knows which version of Prometheus is being configured. + + + If neither `spec.image` nor `spec.baseImage` are defined, the operator + will use the latest upstream version of Prometheus available at the time + when the operator was released. + type: string + imagePullPolicy: + description: |- + Image pull policy for the 'prometheus', 'init-config-reloader' and 'config-reloader' containers. + See https://kubernetes.io/docs/concepts/containers/images/#image-pull-policy for more details. + enum: + - "" + - Always + - Never + - IfNotPresent + type: string + imagePullSecrets: + description: |- + An optional list of references to Secrets in the same namespace + to use for pulling images from registries. + See http://kubernetes.io/docs/user-guide/images#specifying-imagepullsecrets-on-a-pod + items: + description: |- + LocalObjectReference contains enough information to let you locate the + referenced object inside the same namespace. + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + description: |- + InitContainers allows injecting initContainers to the Pod definition. Those + can be used to e.g. fetch secrets for injection into the Prometheus + configuration from external sources. Any errors during the execution of + an initContainer will lead to a restart of the Pod. More info: + https://kubernetes.io/docs/concepts/workloads/pods/init-containers/ + InitContainers described here modify an operator generated init + containers if they share the same name and modifications are done via a + strategic merge patch. + + + The names of init container name managed by the operator are: + * `init-config-reloader`. + + + Overriding init containers is entirely outside the scope of what the + maintainers will support and by doing so, you accept that this behaviour + may break at any time without notice. + items: + description: A single application container that you want to run + within a pod. + properties: + args: + description: |- + Arguments to the entrypoint. + The container image's CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + command: + description: |- + Entrypoint array. Not executed within a shell. + The container image's ENTRYPOINT is used if this is not provided. + Variable references $(VAR_NAME) are expanded using the container's environment. If a variable + cannot be resolved, the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)". Escaped references will never be expanded, regardless + of whether the variable exists or not. Cannot be updated. + More info: https://kubernetes.io/docs/tasks/inject-data-application/define-command-argument-container/#running-a-command-in-a-shell + items: + type: string + type: array + env: + description: |- + List of environment variables to set in the container. + Cannot be updated. + items: + description: EnvVar represents an environment variable present + in a Container. + properties: + name: + description: Name of the environment variable. Must be + a C_IDENTIFIER. + type: string + value: + description: |- + Variable references $(VAR_NAME) are expanded + using the previously defined environment variables in the container and + any service environment variables. If a variable cannot be resolved, + the reference in the input string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the $(VAR_NAME) syntax: i.e. + "$$(VAR_NAME)" will produce the string literal "$(VAR_NAME)". + Escaped references will never be expanded, regardless of whether the variable + exists or not. + Defaults to "". + type: string + valueFrom: + description: Source for the environment variable's value. + Cannot be used if value is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap or + its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: |- + Selects a field of the pod: supports metadata.name, metadata.namespace, `metadata.labels['']`, `metadata.annotations['']`, + spec.nodeName, spec.serviceAccountName, status.hostIP, status.podIP, status.podIPs. + properties: + apiVersion: + description: Version of the schema the FieldPath + is written in terms of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: |- + Selects a resource of the container: only resources limits and requests + (limits.cpu, limits.memory, limits.ephemeral-storage, requests.cpu, requests.memory and requests.ephemeral-storage) are currently supported. + properties: + containerName: + description: 'Container name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output format of the + exposed resources, defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret in the pod's + namespace + properties: + key: + description: The key of the secret to select from. Must + be a valid secret key. + type: string + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret or its + key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: |- + List of sources to populate environment variables in the container. + The keys defined within a source must be a C_IDENTIFIER. All invalid keys + will be reported as an event when the container is starting. When a key exists in multiple + sources, the value associated with the last source will take precedence. + Values defined by an Env with a duplicate key will take precedence. + Cannot be updated. + items: + description: EnvFromSource represents the source of a set + of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the ConfigMap must be + defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend to each + key in the ConfigMap. Must be a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: |- + Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, uid? + type: string + optional: + description: Specify whether the Secret must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: |- + Container image name. + More info: https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level config management to default or override + container images in workload controllers like Deployments and StatefulSets. + type: string + imagePullPolicy: + description: |- + Image pull policy. + One of Always, Never, IfNotPresent. + Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + type: string + lifecycle: + description: |- + Actions that the management system should take in response to container lifecycle events. + Cannot be updated. + properties: + postStart: + description: |- + PostStart is called immediately after a container is created. If the handler fails, + the container is terminated and restarted according to its restart policy. + Other management of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: |- + PreStop is called immediately before a container is terminated due to an + API request or management event such as liveness/startup probe failure, + preemption, resource contention, etc. The handler is not called if the + container crashes or exits. The Pod's termination grace period countdown begins before the + PreStop hook is executed. Regardless of the outcome of the handler, the + container will eventually terminate within the Pod's termination grace + period (unless delayed by finalizers). Other management of the container blocks until the hook completes + or until the termination grace period is reached. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. + HTTP allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + sleep: + description: Sleep represents the duration that the + container should sleep before being terminated. + properties: + seconds: + description: Seconds is the number of seconds to + sleep. + format: int64 + type: integer + required: + - seconds + type: object + tcpSocket: + description: |- + Deprecated. TCPSocket is NOT supported as a LifecycleHandler and kept + for the backward compatibility. There are no validation of this field and + lifecycle hooks will fail in runtime when tcp handler is specified. + properties: + host: + description: 'Optional: Host name to connect to, + defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: |- + Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + name: + description: |- + Name of the container specified as a DNS_LABEL. + Each container in a pod must have a unique name (DNS_LABEL). + Cannot be updated. + type: string + ports: + description: |- + List of ports to expose from the container. Not specifying a port here + DOES NOT prevent that port from being exposed. Any port which is + listening on the default "0.0.0.0" address inside a container will be + accessible from the network. + Modifying this array with strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + Cannot be updated. + items: + description: ContainerPort represents a network port in a + single container. + properties: + containerPort: + description: |- + Number of port to expose on the pod's IP address. + This must be a valid port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external port to. + type: string + hostPort: + description: |- + Number of port to expose on the host. + If specified, this must be a valid port number, 0 < x < 65536. + If HostNetwork is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: |- + If specified, this must be an IANA_SVC_NAME and unique within the pod. Each + named port in a pod must have a unique name. Name for the port that can be + referred to by services. + type: string + protocol: + default: TCP + description: |- + Protocol for port. Must be UDP, TCP, or SCTP. + Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: |- + Periodic probe of container service readiness. + Container will be removed from service endpoints if the probe fails. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents resource resize + policy for the container. + properties: + resourceName: + description: |- + Name of the resource to which this resource resize policy applies. + Supported values: cpu, memory. + type: string + restartPolicy: + description: |- + Restart policy to apply when specified resource is resized. + If not specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: |- + Compute Resources required by this container. + Cannot be updated. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + properties: + claims: + description: |- + Claims lists the names of resources, defined in spec.resourceClaims, + that are used by this container. + + + This is an alpha field and requires enabling the + DynamicResourceAllocation feature gate. + + + This field is immutable. It can only be set for containers. + items: + description: ResourceClaim references one entry in PodSpec.ResourceClaims. + properties: + name: + description: |- + Name must match the name of one entry in pod.spec.resourceClaims of + the Pod where this field is used. It makes that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Limits describes the maximum amount of compute resources allowed. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: |- + Requests describes the minimum amount of compute resources required. + If Requests is omitted for a container, it defaults to Limits if that is explicitly specified, + otherwise to an implementation-defined value. Requests cannot exceed Limits. + More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + type: object + type: object + restartPolicy: + description: |- + RestartPolicy defines the restart behavior of individual containers in a pod. + This field may only be set for init containers, and the only allowed value is "Always". + For non-init containers or when this field is not specified, + the restart behavior is defined by the Pod's restart policy and the container type. + Setting the RestartPolicy as "Always" for the init container will have the following effect: + this init container will be continually restarted on + exit until all regular containers have terminated. Once all regular + containers have completed, all init containers with restartPolicy "Always" + will be shut down. This lifecycle differs from normal init containers and + is often referred to as a "sidecar" container. Although this init + container still starts in the init container sequence, it does not wait + for the container to complete before proceeding to the next init + container. Instead, the next init container starts immediately after this + init container is started, or after any startupProbe has successfully + completed. + type: string + securityContext: + description: |- + SecurityContext defines the security options the container should be run with. + If set, the fields of SecurityContext override the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ + properties: + allowPrivilegeEscalation: + description: |- + AllowPrivilegeEscalation controls whether a process can gain more + privileges than its parent process. This bool directly controls if + the no_new_privs flag will be set on the container process. + AllowPrivilegeEscalation is true always when the container is: + 1) run as Privileged + 2) has CAP_SYS_ADMIN + Note that this field cannot be set when spec.os.name is windows. + type: boolean + capabilities: + description: |- + The capabilities to add/drop when running containers. + Defaults to the default set of capabilities granted by the container runtime. + Note that this field cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX capabilities + type + type: string + type: array + type: object + privileged: + description: |- + Run container in privileged mode. + Processes in privileged containers are essentially equivalent to root on the host. + Defaults to false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + procMount: + description: |- + procMount denotes the type of proc mount to use for the containers. + The default is DefaultProcMount which uses the container runtime defaults for + readonly paths and masked paths. + This requires the ProcMountType feature flag to be enabled. + Note that this field cannot be set when spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: |- + Whether this container has a read-only root filesystem. + Default is false. + Note that this field cannot be set when spec.os.name is windows. + type: boolean + runAsGroup: + description: |- + The GID to run the entrypoint of the container process. + Uses runtime default if unset. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: |- + Indicates that the container must run as a non-root user. + If true, the Kubelet will validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start the container if it does. + If unset or false, no such validation will be performed. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: boolean + runAsUser: + description: |- + The UID to run the entrypoint of the container process. + Defaults to user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: |- + The SELinux context to be applied to the container. + If unspecified, the container runtime will allocate a random SELinux context for each + container. May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that applies + to the container. + type: string + role: + description: Role is a SELinux role label that applies + to the container. + type: string + type: + description: Type is a SELinux type label that applies + to the container. + type: string + user: + description: User is a SELinux user label that applies + to the container. + type: string + type: object + seccompProfile: + description: |- + The seccomp options to use by this container. If seccomp options are + provided at both the pod & container level, the container options + override the pod options. + Note that this field cannot be set when spec.os.name is windows. + properties: + localhostProfile: + description: |- + localhostProfile indicates a profile defined in a file on the node should be used. + The profile must be preconfigured on the node to work. + Must be a descending path, relative to the kubelet's configured seccomp profile location. + Must be set if type is "Localhost". Must NOT be set for any other type. + type: string + type: + description: |- + type indicates which kind of seccomp profile will be applied. + Valid options are: + + + Localhost - a profile defined in a file on the node should be used. + RuntimeDefault - the container runtime default profile should be used. + Unconfined - no profile should be applied. + type: string + required: + - type + type: object + windowsOptions: + description: |- + The Windows specific settings applied to all containers. + If unspecified, the options from the PodSecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name is linux. + properties: + gmsaCredentialSpec: + description: |- + GMSACredentialSpec is where the GMSA admission webhook + (https://github.com/kubernetes-sigs/windows-gmsa) inlines the contents of the + GMSA credential spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name of the + GMSA credential spec to use. + type: string + hostProcess: + description: |- + HostProcess determines if a container should be run as a 'Host Process' container. + All of a Pod's containers must have the same effective HostProcess value + (it is not allowed to have a mix of HostProcess containers and non-HostProcess containers). + In addition, if HostProcess is true then HostNetwork must also be set to true. + type: boolean + runAsUserName: + description: |- + The UserName in Windows to run the entrypoint of the container process. + Defaults to the user specified in image metadata if unspecified. + May also be set in PodSecurityContext. If set in both SecurityContext and + PodSecurityContext, the value specified in SecurityContext takes precedence. + type: string + type: object + type: object + startupProbe: + description: |- + StartupProbe indicates that the Pod has successfully initialized. + If specified, no other probes are executed until this completes successfully. + If this probe fails, the Pod will be restarted, just as if the livenessProbe failed. + This can be used to provide different probe parameters at the beginning of a Pod's lifecycle, + when it might take a long time to load data or warm a cache, than during steady-state operation. + This cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + properties: + exec: + description: Exec specifies the action to take. + properties: + command: + description: |- + Command is the command line to execute inside the container, the working directory for the + command is root ('/') in the container's filesystem. The command is simply exec'd, it is + not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use + a shell, you need to explicitly call out to that shell. + Exit status of 0 is treated as live/healthy and non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: |- + Minimum consecutive failures for the probe to be considered failed after having succeeded. + Defaults to 3. Minimum value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving a GRPC port. + properties: + port: + description: Port number of the gRPC service. Number + must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: |- + Service is the name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + + + If this is not specified, the default behavior is defined by gRPC. + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request to perform. + properties: + host: + description: |- + Host name to connect to, defaults to the pod IP. You probably want to set + "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in the request. HTTP + allows repeated headers. + items: + description: HTTPHeader describes a custom header + to be used in HTTP probes + properties: + name: + description: |- + The header field name. + This will be canonicalized upon output, so case-variant names will be understood as the same header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Name or number of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: |- + Scheme to use for connecting to the host. + Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: |- + Number of seconds after the container has started before liveness probes are initiated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + periodSeconds: + description: |- + How often (in seconds) to perform the probe. + Default to 10 seconds. Minimum value is 1. + format: int32 + type: integer + successThreshold: + description: |- + Minimum consecutive successes for the probe to be considered successful after having failed. + Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action involving a TCP + port. + properties: + host: + description: 'Optional: Host name to connect to, defaults + to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: |- + Number or name of the port to access on the container. + Number must be in the range 1 to 65535. + Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: |- + Optional duration in seconds the pod needs to terminate gracefully upon probe failure. + The grace period is the duration in seconds after the processes running in the pod are sent + a termination signal and the time when the processes are forcibly halted with a kill signal. + Set this value longer than the expected cleanup time for your process. + If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this + value overrides the value provided by the pod spec. + Value must be non-negative integer. The value zero indicates stop immediately via + the kill signal (no opportunity to shut down). + This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate. + Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset. + format: int64 + type: integer + timeoutSeconds: + description: |- + Number of seconds after which the probe times out. + Defaults to 1 second. Minimum value is 1. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes + format: int32 + type: integer + type: object + stdin: + description: |- + Whether this container should allocate a buffer for stdin in the container runtime. If this + is not set, reads from stdin in the container will always result in EOF. + Default is false. + type: boolean + stdinOnce: + description: |- + Whether the container runtime should close the stdin channel after it has been opened by + a single attach. When stdin is true the stdin stream will remain open across multiple attach + sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the + first client attaches to stdin, and then remains open and accepts data until the client disconnects, + at which time stdin is closed and remains closed until the container is restarted. If this + flag is false, a container processes that reads from stdin will never receive an EOF. + Default is false + type: boolean + terminationMessagePath: + description: |- + Optional: Path at which the file to which the container's termination message + will be written is mounted into the container's filesystem. + Message written is intended to be brief final status, such as an assertion failure message. + Will be truncated by the node if greater than 4096 bytes. The total message length across + all containers will be limited to 12kb. + Defaults to /dev/termination-log. + Cannot be updated. + type: string + terminationMessagePolicy: + description: |- + Indicate how the termination message should be populated. File will use the contents of + terminationMessagePath to populate the container status message on both success and failure. + FallbackToLogsOnError will use the last chunk of container log output if the termination + message file is empty and the container exited with an error. + The log output is limited to 2048 bytes or 80 lines, whichever is smaller. + Defaults to File. + Cannot be updated. + type: string + tty: + description: |- + Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. + Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block devices to be + used by the container. + items: + description: volumeDevice describes a mapping of a raw block + device within a container. + properties: + devicePath: + description: devicePath is the path inside of the container + that the device will be mapped to. + type: string + name: + description: name must match the name of a persistentVolumeClaim + in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: |- + Pod volumes to mount into the container's filesystem. + Cannot be updated. + items: + description: VolumeMount describes a mounting of a Volume + within a container. + properties: + mountPath: + description: |- + Path within the container at which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: |- + mountPropagation determines how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is used. + This field is beta in 1.10. + type: string + name: + description: This must match the Name of a Volume. + type: string + readOnly: + description: |- + Mounted read-only if true, read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: |- + Path within the volume from which the container's volume should be mounted. + Defaults to "" (volume's root). + type: string + subPathExpr: + description: |- + Expanded path within the volume from which the container's volume should be mounted. + Behaves similarly to SubPath but environment variable references $(VAR_NAME) are expanded using the container's environment. + Defaults to "" (volume's root). + SubPathExpr and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: |- + Container's working directory. + If not specified, the container runtime's default will be used, which + might be configured in the container image. + Cannot be updated. + type: string + required: + - name + type: object + type: array + keepDroppedTargets: + description: |- + Per-scrape limit on the number of targets dropped by relabeling + that will be kept in memory. 0 means no limit. + + + It requires Prometheus >= v2.47.0. + format: int64 + type: integer + labelLimit: + description: |- + Per-scrape limit on number of labels that will be accepted for a sample. + Only valid in Prometheus versions 2.45.0 and newer. + format: int64 + type: integer + labelNameLengthLimit: + description: |- + Per-scrape limit on length of labels name that will be accepted for a sample. + Only valid in Prometheus versions 2.45.0 and newer. + format: int64 + type: integer + labelValueLengthLimit: + description: |- + Per-scrape limit on length of labels value that will be accepted for a sample. + Only valid in Prometheus versions 2.45.0 and newer. + format: int64 + type: integer + listenLocal: + description: |- + When true, the Prometheus server listens on the loopback address + instead of the Pod IP's address. + type: boolean + logFormat: + description: Log format for Log level for Prometheus and the config-reloader + sidecar. + enum: + - "" + - logfmt + - json + type: string + logLevel: + description: Log level for Prometheus and the config-reloader sidecar. + enum: + - "" + - debug + - info + - warn + - error + type: string + maximumStartupDurationSeconds: + description: |- + Defines the maximum time that the `prometheus` container's startup probe will wait before being considered failed. The startup probe will return success after the WAL replay is complete. + If set, the value should be greater than 60 (seconds). Otherwise it will be equal to 600 seconds (15 minutes). + format: int32 + minimum: 60 + type: integer + minReadySeconds: + description: |- + Minimum number of seconds for which a newly created Pod should be ready + without any of its container crashing for it to be considered available. + Defaults to 0 (pod will be considered available as soon as it is ready) + + + This is an alpha field from kubernetes 1.22 until 1.24 which requires + enabling the StatefulSetMinReadySeconds feature gate. + format: int32 + type: integer + nodeSelector: + additionalProperties: + type: string + description: Defines on which Nodes the Pods are scheduled. + type: object + overrideHonorLabels: + description: |- + When true, Prometheus resolves label conflicts by renaming the labels in + the scraped data to "exported_