diff --git a/agent/app/api/v2/app.go b/agent/app/api/v2/app.go
index bba3e87c3..b6431ee59 100644
--- a/agent/app/api/v2/app.go
+++ b/agent/app/api/v2/app.go
@@ -5,7 +5,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/app/dto"
"github.com/1Panel-dev/1Panel/agent/app/dto/request"
"github.com/1Panel-dev/1Panel/agent/constant"
- "github.com/1Panel-dev/1Panel/agent/global"
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/gin-gonic/gin"
)
@@ -56,11 +55,10 @@ func (b *BaseApi) SyncApp(c *gin.Context) {
}
return
}
- go func() {
- if err = appService.SyncAppListFromRemote(req.TaskID); err != nil {
- global.LOG.Errorf("Synchronization with the App Store failed [%s]", err.Error())
- }
- }()
+ if err = appService.SyncAppListFromRemote(req.TaskID); err != nil {
+ helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
+ return
+ }
helper.SuccessWithData(c, nil)
}
diff --git a/agent/app/dto/app.go b/agent/app/dto/app.go
index 0fe36618f..16bce0905 100644
--- a/agent/app/dto/app.go
+++ b/agent/app/dto/app.go
@@ -96,6 +96,7 @@ type AppProperty struct {
Document string `json:"document"`
Architectures []string `json:"architectures"`
MemoryRequired int `json:"memoryRequired"`
+ GpuSupport bool `json:"gpuSupport"`
}
type AppConfigVersion struct {
diff --git a/agent/app/dto/request/app.go b/agent/app/dto/request/app.go
index 5593cb8cc..47b5fc0fb 100644
--- a/agent/app/dto/request/app.go
+++ b/agent/app/dto/request/app.go
@@ -36,6 +36,7 @@ type AppContainerConfig struct {
DockerCompose string `json:"dockerCompose"`
HostMode bool `json:"hostMode"`
PullImage bool `json:"pullImage"`
+ GpuConfig bool `json:"gpuConfig"`
}
type AppInstalledSearch struct {
diff --git a/agent/app/dto/response/app.go b/agent/app/dto/response/app.go
index c0f0165c7..664e0061f 100644
--- a/agent/app/dto/response/app.go
+++ b/agent/app/dto/response/app.go
@@ -44,6 +44,7 @@ type AppDto struct {
Tags []model.Tag `json:"tags"`
Github string `json:"github"`
Website string `json:"website"`
+ GpuSupport bool `json:"gpuSupport"`
}
type TagDTO struct {
@@ -73,6 +74,7 @@ type AppDetailDTO struct {
HostMode bool `json:"hostMode"`
Architectures string `json:"architectures"`
MemoryRequired int `json:"memoryRequired"`
+ GpuSupport bool `json:"gpuSupport"`
}
type IgnoredApp struct {
diff --git a/agent/app/model/app.go b/agent/app/model/app.go
index 695007f56..071bb5b9d 100644
--- a/agent/app/model/app.go
+++ b/agent/app/model/app.go
@@ -28,6 +28,7 @@ type App struct {
LastModified int `json:"lastModified"`
Architectures string `json:"architectures"`
MemoryRequired int `json:"memoryRequired"`
+ GpuSupport bool `json:"gpuSupport"`
Details []AppDetail `json:"-" gorm:"-:migration"`
TagsKey []string `json:"tags" yaml:"tags" gorm:"-"`
diff --git a/agent/app/service/app.go b/agent/app/service/app.go
index 9249507fe..d2f3ff9c0 100644
--- a/agent/app/service/app.go
+++ b/agent/app/service/app.go
@@ -111,6 +111,7 @@ func (a AppService) PageApp(req request.AppSearch) (interface{}, error) {
Limit: ap.Limit,
Website: ap.Website,
Github: ap.Github,
+ GpuSupport: ap.GpuSupport,
}
appDTOs = append(appDTOs, appDTO)
appTags, err := appTagRepo.GetByAppId(ap.ID)
@@ -263,7 +264,8 @@ func (a AppService) GetAppDetail(appID uint, version, appType string) (response.
appDetailDTO.Enable = false
}
appDetailDTO.Architectures = app.Architectures
- appDetailDTO.MemoryLimit = app.MemoryLimit
+ appDetailDTO.MemoryRequired = app.MemoryRequired
+ appDetailDTO.GpuSupport = app.GpuSupport
return appDetailDTO, nil
}
func (a AppService) GetAppDetailByID(id uint) (*response.AppDetailDTO, error) {
@@ -1057,5 +1059,11 @@ func (a AppService) SyncAppListFromRemote(taskID string) (err error) {
return nil
}, nil)
- return syncTask.Execute()
+ go func() {
+ if err = syncTask.Execute(); err != nil {
+ _ = NewISettingService().Update("AppStoreSyncStatus", constant.Error)
+ }
+ }()
+
+ return nil
}
diff --git a/agent/app/service/app_utils.go b/agent/app/service/app_utils.go
index 21bfdf2ba..918b798f9 100644
--- a/agent/app/service/app_utils.go
+++ b/agent/app/service/app_utils.go
@@ -1120,6 +1120,7 @@ func getApps(oldApps []model.App, items []dto.AppDefine) map[string]model.App {
app.ReadMe = item.ReadMe
app.MemoryRequired = config.MemoryRequired
app.Architectures = strings.Join(config.Architectures, ",")
+ app.GpuSupport = config.GpuSupport
apps[key] = app
}
return apps
@@ -1509,6 +1510,17 @@ func addDockerComposeCommonParam(composeMap map[string]interface{}, serviceName
"cpus": "${CPUS}",
"memory": "${MEMORY_LIMIT}",
}
+ if req.GpuConfig {
+ resource["reservations"] = map[string]interface{}{
+ "devices": []map[string]interface{}{
+ {
+ "driver": "nvidia",
+ "count": "all",
+ "capabilities": []string{"gpu"},
+ },
+ },
+ }
+ }
deploy["resources"] = resource
serviceValue["deploy"] = deploy
diff --git a/agent/init/migration/migrations/init.go b/agent/init/migration/migrations/init.go
index dc5e9fdd7..e48c41285 100644
--- a/agent/init/migration/migrations/init.go
+++ b/agent/init/migration/migrations/init.go
@@ -245,7 +245,7 @@ var AddTaskDB = &gormigrate.Migration{
}
var UpdateApp = &gormigrate.Migration{
- ID: "20240823-update-app",
+ ID: "20240826-update-app",
Migrate: func(tx *gorm.DB) error {
return tx.AutoMigrate(
&model.App{})
diff --git a/frontend/src/api/interface/app.ts b/frontend/src/api/interface/app.ts
index 9f00e30e9..699961bbb 100644
--- a/frontend/src/api/interface/app.ts
+++ b/frontend/src/api/interface/app.ts
@@ -51,6 +51,7 @@ export namespace App {
hostMode?: boolean;
memoryRequired: number;
architectures: string;
+ gpuSupport: boolean;
}
export interface AppReq extends ReqPage {
diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts
index ba6e3be51..c5ae5412f 100644
--- a/frontend/src/lang/modules/en.ts
+++ b/frontend/src/lang/modules/en.ts
@@ -1880,6 +1880,9 @@ const message = {
showCurrentArch: 'Architecture',
syncLocalApp: 'Sync Local App',
memoryRequiredHelper: 'Current application memory requirement {0}',
+ gpuConfig: 'Enable GPU Support',
+ gpuConfigHelper:
+ 'Please ensure the machine has an NVIDIA GPU and that NVIDIA drivers and the NVIDIA Docker Container Toolkit are installed',
},
website: {
website: 'Website',
diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts
index ca541209d..86f9498a0 100644
--- a/frontend/src/lang/modules/tw.ts
+++ b/frontend/src/lang/modules/tw.ts
@@ -1746,6 +1746,8 @@ const message = {
showCurrentArch: '僅顯示當前架構',
syncLocalApp: '同步本地應用',
memoryRequiredHelper: '目前應用記憶體需求 {0}',
+ gpuConfig: '開啟 GPU 支援',
+ gpuConfigHelper: '請確保機器有 NVIDIA GPU 並且安裝 NVIDIA 驅動 和 NVIDIA docker Container Toolkit',
},
website: {
website: '網站',
diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts
index a87c851cd..e3975ef4f 100644
--- a/frontend/src/lang/modules/zh.ts
+++ b/frontend/src/lang/modules/zh.ts
@@ -1747,6 +1747,8 @@ const message = {
showCurrentArch: '仅显示当前服务器架构应用',
syncLocalApp: '同步本地应用',
memoryRequiredHelper: '当前应用内存需求 {0}',
+ gpuConfig: '开启 GPU 支持',
+ gpuConfigHelper: '请确保机器有 NVIDIA GPU 并且安装 NVIDIA 驱动 和 NVIDIA docker Container Toolkit',
},
website: {
website: '网站',
diff --git a/frontend/src/views/app-store/detail/install/index.vue b/frontend/src/views/app-store/detail/install/index.vue
index 79ed369d4..731664575 100644
--- a/frontend/src/views/app-store/detail/install/index.vue
+++ b/frontend/src/views/app-store/detail/install/index.vue
@@ -90,6 +90,10 @@
{{ $t('container.limitHelper', [limits.memory]) }}{{ req.memoryUnit }}B
+
+
+ {{ $t('app.gpuConfigHelper') }}
+
{{ $t('container.forcePullHelper') }}
@@ -170,6 +174,7 @@ const initData = () => ({
appID: '',
pullImage: true,
taskID: '',
+ gpuConfig: false,
});
const req = reactive(initData());
const limits = ref({
@@ -189,6 +194,7 @@ const paramKey = ref(1);
const isHostMode = ref(false);
const taskLogRef = ref();
const memoryRequired = ref(0);
+const gpuSupport = ref(false);
const changeUnit = () => {
if (req.memoryUnit == 'M') {
@@ -237,6 +243,7 @@ const getAppDetail = async (version: string) => {
installData.value.params = res.data.params;
paramKey.value++;
memoryRequired.value = res.data.memoryRequired;
+ gpuSupport.value = res.data.gpuSupport;
} catch (error) {
} finally {
loading.value = false;