Add documentation and local build Dockerfile
- README.md: Build and deployment guide for beginners - Extend-Function.md: Extended files list and version upgrade guide - Unlock-License.md: License check removal documentation - Dockerfile.local: Local source build support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
7ce2e2b810
commit
7e5c7b8c36
29
Dockerfile.local
Normal file
29
Dockerfile.local
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
FROM rockylinux:9 AS builder
|
||||||
|
|
||||||
|
# Install build dependencies
|
||||||
|
RUN dnf install -y git golang make gcc
|
||||||
|
|
||||||
|
# Copy local source
|
||||||
|
WORKDIR /build
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Build
|
||||||
|
RUN go build -v -mod=vendor -o mattermost ./cmd/mattermost
|
||||||
|
|
||||||
|
# Runtime image
|
||||||
|
FROM rockylinux:9-minimal
|
||||||
|
|
||||||
|
RUN microdnf install -y ca-certificates tzdata && microdnf clean all
|
||||||
|
|
||||||
|
WORKDIR /mattermost
|
||||||
|
COPY --from=builder /build/mattermost /mattermost/bin/mattermost
|
||||||
|
COPY --from=builder /build/config /mattermost/config
|
||||||
|
COPY --from=builder /build/i18n /mattermost/i18n
|
||||||
|
COPY --from=builder /build/fonts /mattermost/fonts
|
||||||
|
COPY --from=builder /build/templates /mattermost/templates
|
||||||
|
COPY --from=builder /build/client /mattermost/client
|
||||||
|
|
||||||
|
RUN mkdir -p /mattermost/data /mattermost/logs /mattermost/plugins /mattermost/client/plugins
|
||||||
|
|
||||||
|
EXPOSE 8065
|
||||||
|
ENTRYPOINT ["/mattermost/bin/mattermost"]
|
||||||
325
Extend-Function.md
Normal file
325
Extend-Function.md
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
# Mattermost Community Enterprise - 확장 기능 문서
|
||||||
|
|
||||||
|
이 문서는 Team Edition에서 Enterprise 기능을 활성화하기 위해 생성/수정된 파일과 버전 업그레이드 시 이식해야 할 내용을 정리합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 프로젝트 구조
|
||||||
|
|
||||||
|
```
|
||||||
|
mattermost-community-enterprise/
|
||||||
|
├── enterprise/ # Enterprise 브릿지 (기존)
|
||||||
|
│ └── community_imports.go # enterprise-community 임포트
|
||||||
|
├── enterprise-impl/ # [신규] Enterprise 구현체
|
||||||
|
│ ├── enterprise.go # 메인 등록 파일
|
||||||
|
│ ├── go.mod # 별도 모듈 정의
|
||||||
|
│ ├── go.sum
|
||||||
|
│ ├── ldap/ # LDAP 구현
|
||||||
|
│ ├── saml/ # SAML 구현
|
||||||
|
│ ├── cluster/ # 클러스터링 구현
|
||||||
|
│ ├── metrics/ # Prometheus 메트릭 구현
|
||||||
|
│ ├── compliance/ # 컴플라이언스 구현
|
||||||
|
│ ├── data_retention/ # 데이터 보존 구현
|
||||||
|
│ ├── message_export/ # 메시지 내보내기 구현
|
||||||
|
│ ├── account_migration/ # 계정 마이그레이션 구현
|
||||||
|
│ ├── access_control/ # 접근 제어 구현
|
||||||
|
│ ├── ip_filtering/ # IP 필터링 구현
|
||||||
|
│ ├── notification/ # 알림 구현
|
||||||
|
│ ├── oauthproviders/ # OAuth 프로바이더 구현
|
||||||
|
│ ├── outgoing_oauth_connection/ # 외부 OAuth 연결 구현
|
||||||
|
│ ├── push_proxy/ # 푸시 프록시 구현
|
||||||
|
│ └── searchengine/ # 검색 엔진 구현
|
||||||
|
├── enterprise-community/ # [신규] Enterprise 등록 파일
|
||||||
|
│ ├── imports.go # 모든 구현체 임포트
|
||||||
|
│ ├── ldap/init.go
|
||||||
|
│ ├── saml/init.go
|
||||||
|
│ ├── cluster/init.go
|
||||||
|
│ ├── metrics/init.go
|
||||||
|
│ ├── compliance/init.go
|
||||||
|
│ ├── data_retention/init.go
|
||||||
|
│ ├── message_export/init.go
|
||||||
|
│ ├── account_migration/init.go
|
||||||
|
│ ├── access_control/init.go
|
||||||
|
│ ├── ip_filtering/init.go
|
||||||
|
│ ├── notification/init.go
|
||||||
|
│ ├── outgoing_oauth_connection/init.go
|
||||||
|
│ ├── push_proxy/init.go
|
||||||
|
│ └── searchengine/init.go
|
||||||
|
├── channels/api4/ # [수정됨] API 라이선스 체크 제거
|
||||||
|
│ ├── ldap.go
|
||||||
|
│ ├── saml.go
|
||||||
|
│ ├── user.go
|
||||||
|
│ ├── group.go
|
||||||
|
│ └── scheme.go
|
||||||
|
├── channels/app/platform/ # [수정됨] 메트릭 핸들러
|
||||||
|
│ └── metrics.go
|
||||||
|
├── Dockerfile.local # [신규] 로컬 빌드용 Dockerfile
|
||||||
|
├── Dockerfile.mattermost # [신규] Git 빌드용 Dockerfile
|
||||||
|
├── README.md # [신규] 빌드 가이드
|
||||||
|
├── Extend-Function.md # [신규] 이 문서
|
||||||
|
└── Unlock-License.md # [신규] 라이선스 해제 문서
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 생성된 파일 상세
|
||||||
|
|
||||||
|
### 1. enterprise-impl/ (Enterprise 구현체)
|
||||||
|
|
||||||
|
#### enterprise-impl/enterprise.go
|
||||||
|
|
||||||
|
Enterprise 기능 등록을 위한 메인 파일입니다.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package enterprise
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/mattermost/server/v8/channels/app"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/enterprise-impl/ldap"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/enterprise-impl/cluster"
|
||||||
|
"github.com/mattermost/mattermost/server/v8/enterprise-impl/metrics"
|
||||||
|
// ... 기타 imports
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
app.RegisterLdapInterface(ldap.New)
|
||||||
|
app.RegisterClusterInterface(cluster.New)
|
||||||
|
app.RegisterMetricsInterface(metrics.New)
|
||||||
|
// ... 기타 등록
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### enterprise-impl/ldap/ldap.go
|
||||||
|
|
||||||
|
LDAP 인증 및 동기화 구현체입니다.
|
||||||
|
|
||||||
|
주요 메서드:
|
||||||
|
- `DoLogin()` - LDAP 로그인 처리
|
||||||
|
- `GetUser()` - LDAP에서 사용자 조회
|
||||||
|
- `GetGroup()` - LDAP에서 그룹 조회
|
||||||
|
- `SyncAllUsers()` - 모든 사용자 동기화
|
||||||
|
- `RunTest()` - LDAP 연결 테스트
|
||||||
|
|
||||||
|
#### enterprise-impl/cluster/cluster.go
|
||||||
|
|
||||||
|
Redis 기반 클러스터링 구현체입니다.
|
||||||
|
|
||||||
|
주요 메서드:
|
||||||
|
- `StartInterNodeCommunication()` - 노드 간 통신 시작
|
||||||
|
- `RegisterClusterMessageHandler()` - 메시지 핸들러 등록
|
||||||
|
- `SendClusterMessage()` - 클러스터 메시지 전송
|
||||||
|
- `GetClusterStats()` - 클러스터 상태 조회
|
||||||
|
|
||||||
|
#### enterprise-impl/metrics/metrics.go
|
||||||
|
|
||||||
|
Prometheus 메트릭 수집 구현체입니다.
|
||||||
|
|
||||||
|
주요 메서드:
|
||||||
|
- `Register()` - 메트릭 등록
|
||||||
|
- `Handler()` - HTTP 핸들러 반환
|
||||||
|
- `IncrementHTTPRequest()` - HTTP 요청 카운트
|
||||||
|
- `ObserveAPIEndpointDuration()` - API 응답 시간 측정
|
||||||
|
|
||||||
|
### 2. enterprise-community/ (등록 파일)
|
||||||
|
|
||||||
|
#### enterprise-community/imports.go
|
||||||
|
|
||||||
|
모든 Enterprise 구현체를 임포트하여 init()이 실행되도록 합니다.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package enterprise_community
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "github.com/mattermost/mattermost/server/v8/enterprise-community/ldap"
|
||||||
|
_ "github.com/mattermost/mattermost/server/v8/enterprise-community/cluster"
|
||||||
|
_ "github.com/mattermost/mattermost/server/v8/enterprise-community/metrics"
|
||||||
|
// ... 기타 imports
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### enterprise-community/ldap/init.go
|
||||||
|
|
||||||
|
LDAP 구현체를 app에 등록합니다.
|
||||||
|
|
||||||
|
```go
|
||||||
|
package ldap
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/mattermost/mattermost/server/v8/channels/app"
|
||||||
|
ldapImpl "github.com/mattermost/mattermost/server/v8/enterprise-impl/ldap"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
app.RegisterLdapInterface(ldapImpl.New)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 수정된 파일
|
||||||
|
|
||||||
|
#### channels/api4/ldap.go
|
||||||
|
|
||||||
|
LDAP 관련 API에서 라이선스 체크 제거:
|
||||||
|
- `syncLdap()` - LDAP 동기화
|
||||||
|
- `testLdap()` - LDAP 연결 테스트
|
||||||
|
- `getLdapGroups()` - LDAP 그룹 조회
|
||||||
|
- `linkLdapGroup()` - LDAP 그룹 연결
|
||||||
|
- `unlinkLdapGroup()` - LDAP 그룹 연결 해제
|
||||||
|
- `migrateIdLdap()` - LDAP ID 마이그레이션
|
||||||
|
- `createLdapPublicCertificate()` - 인증서 생성
|
||||||
|
|
||||||
|
#### channels/api4/scheme.go
|
||||||
|
|
||||||
|
커스텀 권한 스키마 API에서 라이선스 체크 제거:
|
||||||
|
- `createScheme()` - 스키마 생성
|
||||||
|
- `patchScheme()` - 스키마 수정
|
||||||
|
- `deleteScheme()` - 스키마 삭제
|
||||||
|
|
||||||
|
#### channels/api4/group.go
|
||||||
|
|
||||||
|
그룹 관련 API에서 라이선스 체크 제거:
|
||||||
|
- `getGroupsByTeam()` - 팀별 그룹 조회
|
||||||
|
- `getGroupsByChannel()` - 채널별 그룹 조회
|
||||||
|
|
||||||
|
#### channels/api4/user.go
|
||||||
|
|
||||||
|
사용자 마이그레이션 API에서 라이선스 체크 제거:
|
||||||
|
- `migrateAuthToLdap()` - LDAP 인증 마이그레이션
|
||||||
|
- `migrateAuthToSaml()` - SAML 인증 마이그레이션
|
||||||
|
|
||||||
|
#### channels/app/platform/metrics.go
|
||||||
|
|
||||||
|
메트릭 라우터에 `/metrics` 핸들러 등록 추가:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// MetricsHandlerProvider 인터페이스 추가
|
||||||
|
type MetricsHandlerProvider interface {
|
||||||
|
Handler() http.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
// initMetricsRouter()에 핸들러 등록 코드 추가
|
||||||
|
if pm.metricsImpl != nil {
|
||||||
|
if handlerProvider, ok := pm.metricsImpl.(MetricsHandlerProvider); ok {
|
||||||
|
pm.router.Handle("/metrics", handlerProvider.Handler())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 버전 업그레이드 가이드
|
||||||
|
|
||||||
|
Mattermost 새 버전으로 업그레이드할 때 다음 파일들을 이식해야 합니다.
|
||||||
|
|
||||||
|
### 필수 이식 파일
|
||||||
|
|
||||||
|
1. **enterprise-impl/ 전체 디렉토리**
|
||||||
|
- 새 버전의 einterfaces에 맞게 수정 필요
|
||||||
|
- 인터페이스 변경 시 구현체 업데이트
|
||||||
|
|
||||||
|
2. **enterprise-community/ 전체 디렉토리**
|
||||||
|
- 새로운 Enterprise 기능 추가 시 init 파일 추가
|
||||||
|
- app 패키지 경로 변경 시 import 수정
|
||||||
|
|
||||||
|
3. **enterprise/community_imports.go**
|
||||||
|
- enterprise-community 패키지 임포트 유지
|
||||||
|
|
||||||
|
### API 라이선스 체크 재제거
|
||||||
|
|
||||||
|
새 버전에서 다음 파일들의 라이선스 체크를 다시 제거해야 합니다:
|
||||||
|
|
||||||
|
1. **channels/api4/ldap.go**
|
||||||
|
- `c.App.Channels().License() == nil` 조건문 찾아서 제거
|
||||||
|
- `!*c.App.Channels().License().Features.LDAP` 조건 제거
|
||||||
|
|
||||||
|
2. **channels/api4/scheme.go**
|
||||||
|
- `!*c.App.Channels().License().Features.CustomPermissionsSchemes` 조건 제거
|
||||||
|
|
||||||
|
3. **channels/api4/group.go**
|
||||||
|
- `!*c.App.Channels().License().Features.LDAPGroups` 조건 제거
|
||||||
|
|
||||||
|
4. **channels/api4/user.go**
|
||||||
|
- LDAP/SAML 마이그레이션 라이선스 체크 제거
|
||||||
|
|
||||||
|
5. **channels/app/platform/metrics.go**
|
||||||
|
- `MetricsHandlerProvider` 인터페이스 추가
|
||||||
|
- `/metrics` 핸들러 등록 코드 추가
|
||||||
|
|
||||||
|
### 이식 스크립트 예시
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# upgrade-mattermost.sh
|
||||||
|
|
||||||
|
NEW_VERSION=$1
|
||||||
|
OLD_DIR="mattermost-community-enterprise"
|
||||||
|
NEW_DIR="mattermost-server-$NEW_VERSION"
|
||||||
|
|
||||||
|
# 1. 새 버전 다운로드
|
||||||
|
git clone https://github.com/mattermost/mattermost.git $NEW_DIR
|
||||||
|
cd $NEW_DIR/server
|
||||||
|
|
||||||
|
# 2. Enterprise 구현체 복사
|
||||||
|
cp -r $OLD_DIR/enterprise-impl ./
|
||||||
|
cp -r $OLD_DIR/enterprise-community ./
|
||||||
|
|
||||||
|
# 3. community_imports.go 복사
|
||||||
|
cp $OLD_DIR/enterprise/community_imports.go ./enterprise/
|
||||||
|
|
||||||
|
# 4. go.mod 업데이트 (enterprise-impl 추가)
|
||||||
|
echo 'replace github.com/mattermost/mattermost/server/v8/enterprise-impl => ./enterprise-impl' >> go.mod
|
||||||
|
|
||||||
|
# 5. vendor 업데이트
|
||||||
|
go mod vendor
|
||||||
|
|
||||||
|
echo "이제 API 파일에서 라이선스 체크를 수동으로 제거하세요"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 라이선스 체크 자동 제거 스크립트
|
||||||
|
|
||||||
|
```bash
|
||||||
|
#!/bin/bash
|
||||||
|
# remove-license-checks.sh
|
||||||
|
|
||||||
|
# LDAP 라이선스 체크 제거
|
||||||
|
sed -i '/c\.App\.Channels()\.License() == nil.*LDAP/d' channels/api4/ldap.go
|
||||||
|
sed -i '/!.*License()\.Features\.LDAP/d' channels/api4/ldap.go
|
||||||
|
|
||||||
|
# Scheme 라이선스 체크 제거
|
||||||
|
sed -i '/License()\.Features\.CustomPermissionsSchemes/d' channels/api4/scheme.go
|
||||||
|
|
||||||
|
# Group 라이선스 체크 제거
|
||||||
|
sed -i '/License()\.Features\.LDAPGroups/d' channels/api4/group.go
|
||||||
|
|
||||||
|
echo "라이선스 체크 제거 완료. 빌드 테스트를 실행하세요."
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## einterfaces 매핑
|
||||||
|
|
||||||
|
| 인터페이스 | 구현 파일 | 등록 함수 |
|
||||||
|
|-----------|----------|----------|
|
||||||
|
| LdapInterface | enterprise-impl/ldap/ldap.go | app.RegisterLdapInterface |
|
||||||
|
| SamlInterface | enterprise-impl/saml/saml.go | app.RegisterSamlInterface |
|
||||||
|
| ClusterInterface | enterprise-impl/cluster/cluster.go | app.RegisterClusterInterface |
|
||||||
|
| MetricsInterface | enterprise-impl/metrics/metrics.go | app.RegisterMetricsInterface |
|
||||||
|
| ComplianceInterface | enterprise-impl/compliance/compliance.go | app.RegisterComplianceInterface |
|
||||||
|
| DataRetentionInterface | enterprise-impl/data_retention/data_retention.go | app.RegisterDataRetentionInterface |
|
||||||
|
| MessageExportInterface | enterprise-impl/message_export/message_export.go | app.RegisterMessageExportInterface |
|
||||||
|
| AccountMigrationInterface | enterprise-impl/account_migration/account_migration.go | app.RegisterAccountMigrationInterface |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 주의사항
|
||||||
|
|
||||||
|
1. **UI 라이선스 체크**: 웹 클라이언트(client/ 디렉토리)에도 라이선스 체크가 있을 수 있습니다. JavaScript 파일은 minified 상태라 수정이 어렵습니다.
|
||||||
|
|
||||||
|
2. **버전 호환성**: 이 구현체는 Mattermost v9.x를 기준으로 작성되었습니다. 메이저 버전이 변경되면 인터페이스 시그니처가 달라질 수 있습니다.
|
||||||
|
|
||||||
|
3. **테스트**: 업그레이드 후 반드시 모든 Enterprise 기능을 테스트하세요:
|
||||||
|
- LDAP 로그인
|
||||||
|
- 클러스터 동기화
|
||||||
|
- Prometheus 메트릭 (/metrics 엔드포인트)
|
||||||
|
- 커스텀 권한 스키마 생성/수정
|
||||||
|
|
||||||
|
4. **상용 사용**: 이 프로젝트는 학습 및 개인 사용 목적입니다. 상용 환경에서는 Mattermost 공식 라이선스를 구매하세요.
|
||||||
328
README.md
Normal file
328
README.md
Normal file
@ -0,0 +1,328 @@
|
|||||||
|
# Mattermost Community Enterprise
|
||||||
|
|
||||||
|
라이선스 없이 Enterprise 기능을 사용할 수 있는 Mattermost 오픈소스 빌드입니다.
|
||||||
|
|
||||||
|
## 시스템 요구사항
|
||||||
|
|
||||||
|
- **OS**: Rocky Linux 9 / CentOS 9 / RHEL 9 (권장) 또는 Ubuntu 22.04+
|
||||||
|
- **CPU**: 최소 2 Core
|
||||||
|
- **RAM**: 최소 2GB (권장 4GB)
|
||||||
|
- **디스크**: 최소 20GB
|
||||||
|
- **네트워크**: 인터넷 연결 필요 (빌드 시)
|
||||||
|
|
||||||
|
## 빠른 시작 (Docker 사용)
|
||||||
|
|
||||||
|
### 1. 소스 코드 받기
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone http://10.0.4.213:3000/claude/mattermost-community-enterprise.git
|
||||||
|
cd mattermost-community-enterprise
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Docker 이미지 빌드
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 로컬 소스로 빌드 (권장)
|
||||||
|
docker build -f Dockerfile.local -t mattermost-community:latest .
|
||||||
|
|
||||||
|
# 또는 Git에서 직접 빌드 (네트워크 필요)
|
||||||
|
docker build -f Dockerfile.mattermost -t mattermost-community:latest .
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Docker Compose로 실행
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# docker-compose.yml 파일 생성 (아래 내용 참고)
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**docker-compose.yml 예시:**
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: '3.8'
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:15
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: mattermost
|
||||||
|
POSTGRES_USER: mmuser
|
||||||
|
POSTGRES_PASSWORD: mmpassword
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
mattermost:
|
||||||
|
image: mattermost-community:latest
|
||||||
|
depends_on:
|
||||||
|
- postgres
|
||||||
|
ports:
|
||||||
|
- "8065:8065"
|
||||||
|
environment:
|
||||||
|
MM_SQLSETTINGS_DRIVERNAME: postgres
|
||||||
|
MM_SQLSETTINGS_DATASOURCE: postgres://mmuser:mmpassword@postgres:5432/mattermost?sslmode=disable
|
||||||
|
volumes:
|
||||||
|
- mattermost_data:/mattermost/data
|
||||||
|
- mattermost_logs:/mattermost/logs
|
||||||
|
- mattermost_plugins:/mattermost/plugins
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
|
mattermost_data:
|
||||||
|
mattermost_logs:
|
||||||
|
mattermost_plugins:
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 접속
|
||||||
|
|
||||||
|
브라우저에서 `http://서버IP:8065` 로 접속합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 수동 빌드 (Docker 없이)
|
||||||
|
|
||||||
|
### 1. 의존성 설치
|
||||||
|
|
||||||
|
**Rocky Linux / CentOS 9:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo dnf install -y git golang make gcc
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ubuntu 22.04:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install -y git golang-go make gcc
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Go 버전 확인
|
||||||
|
|
||||||
|
Go 1.21 이상이 필요합니다.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
go version
|
||||||
|
# go version go1.21.x linux/amd64
|
||||||
|
```
|
||||||
|
|
||||||
|
Go 버전이 낮으면 최신 버전을 설치합니다:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Rocky Linux
|
||||||
|
sudo dnf module enable go-toolset:rhel9
|
||||||
|
sudo dnf install -y go-toolset
|
||||||
|
|
||||||
|
# 또는 직접 설치
|
||||||
|
wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz
|
||||||
|
sudo tar -C /usr/local -xzf go1.22.0.linux-amd64.tar.gz
|
||||||
|
export PATH=$PATH:/usr/local/go/bin
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. 소스 코드 받기
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone http://10.0.4.213:3000/claude/mattermost-community-enterprise.git
|
||||||
|
cd mattermost-community-enterprise
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 빌드
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# vendor 디렉토리 사용 (오프라인/에어갭 환경)
|
||||||
|
go build -v -mod=vendor -o mattermost ./cmd/mattermost
|
||||||
|
|
||||||
|
# 또는 온라인 환경에서 최신 의존성 사용
|
||||||
|
go mod download
|
||||||
|
go build -v -o mattermost ./cmd/mattermost
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 디렉토리 구조 준비
|
||||||
|
|
||||||
|
```bash
|
||||||
|
mkdir -p /opt/mattermost/{bin,config,data,logs,plugins,client/plugins}
|
||||||
|
|
||||||
|
# 바이너리 복사
|
||||||
|
cp mattermost /opt/mattermost/bin/
|
||||||
|
|
||||||
|
# 설정 및 리소스 복사
|
||||||
|
cp -r config/* /opt/mattermost/config/
|
||||||
|
cp -r i18n /opt/mattermost/
|
||||||
|
cp -r fonts /opt/mattermost/
|
||||||
|
cp -r templates /opt/mattermost/
|
||||||
|
cp -r client/* /opt/mattermost/client/
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 데이터베이스 설정
|
||||||
|
|
||||||
|
**PostgreSQL 설치 및 설정:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# PostgreSQL 설치
|
||||||
|
sudo dnf install -y postgresql-server postgresql
|
||||||
|
sudo postgresql-setup --initdb
|
||||||
|
sudo systemctl enable --now postgresql
|
||||||
|
|
||||||
|
# 데이터베이스 생성
|
||||||
|
sudo -u postgres psql <<EOF
|
||||||
|
CREATE DATABASE mattermost;
|
||||||
|
CREATE USER mmuser WITH PASSWORD 'mmpassword';
|
||||||
|
GRANT ALL PRIVILEGES ON DATABASE mattermost TO mmuser;
|
||||||
|
ALTER DATABASE mattermost OWNER TO mmuser;
|
||||||
|
\c mattermost
|
||||||
|
GRANT ALL ON SCHEMA public TO mmuser;
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. 설정 파일 수정
|
||||||
|
|
||||||
|
`/opt/mattermost/config/config.json` 수정:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"SqlSettings": {
|
||||||
|
"DriverName": "postgres",
|
||||||
|
"DataSource": "postgres://mmuser:mmpassword@localhost:5432/mattermost?sslmode=disable"
|
||||||
|
},
|
||||||
|
"ServiceSettings": {
|
||||||
|
"SiteURL": "http://서버IP:8065",
|
||||||
|
"ListenAddress": ":8065"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. 실행
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/mattermost
|
||||||
|
./bin/mattermost
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. Systemd 서비스 등록 (선택)
|
||||||
|
|
||||||
|
`/etc/systemd/system/mattermost.service` 파일 생성:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[Unit]
|
||||||
|
Description=Mattermost
|
||||||
|
After=network.target postgresql.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
ExecStart=/opt/mattermost/bin/mattermost
|
||||||
|
WorkingDirectory=/opt/mattermost
|
||||||
|
User=mattermost
|
||||||
|
Group=mattermost
|
||||||
|
Restart=always
|
||||||
|
RestartSec=10
|
||||||
|
LimitNOFILE=49152
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
```
|
||||||
|
|
||||||
|
서비스 활성화:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# mattermost 사용자 생성
|
||||||
|
sudo useradd -r -s /sbin/nologin mattermost
|
||||||
|
sudo chown -R mattermost:mattermost /opt/mattermost
|
||||||
|
|
||||||
|
# 서비스 시작
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now mattermost
|
||||||
|
sudo systemctl status mattermost
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## HA 클러스터 구성
|
||||||
|
|
||||||
|
고가용성을 위해 여러 Mattermost 인스턴스를 클러스터로 구성할 수 있습니다.
|
||||||
|
|
||||||
|
### Redis 설정
|
||||||
|
|
||||||
|
클러스터 모드에서는 Redis가 필요합니다:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -d --name redis -p 6379:6379 redis:7
|
||||||
|
```
|
||||||
|
|
||||||
|
### 환경 변수 설정
|
||||||
|
|
||||||
|
각 Mattermost 노드에서:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export MM_CLUSTERSETTINGS_ENABLE=true
|
||||||
|
export MM_CLUSTERSETTINGS_CLUSTERNAME=mattermost-cluster
|
||||||
|
export MM_CLUSTERSETTINGS_REDISHOST=redis호스트:6379
|
||||||
|
```
|
||||||
|
|
||||||
|
### HAProxy 로드밸런서
|
||||||
|
|
||||||
|
```
|
||||||
|
frontend mattermost
|
||||||
|
bind *:80
|
||||||
|
default_backend mattermost_servers
|
||||||
|
|
||||||
|
backend mattermost_servers
|
||||||
|
balance roundrobin
|
||||||
|
cookie SERVERID insert indirect nocache
|
||||||
|
server mm1 10.0.4.112:8065 check cookie mm1
|
||||||
|
server mm2 10.0.4.49:8065 check cookie mm2
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 트러블슈팅
|
||||||
|
|
||||||
|
### 빌드 오류: "cannot find module"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# vendor 디렉토리 재생성
|
||||||
|
go mod vendor
|
||||||
|
```
|
||||||
|
|
||||||
|
### 실행 오류: "config.json not found"
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 설정 파일 위치 지정
|
||||||
|
./mattermost --config /opt/mattermost/config/config.json
|
||||||
|
```
|
||||||
|
|
||||||
|
### 데이터베이스 연결 실패
|
||||||
|
|
||||||
|
1. PostgreSQL 서비스 상태 확인: `systemctl status postgresql`
|
||||||
|
2. 연결 테스트: `psql -h localhost -U mmuser -d mattermost`
|
||||||
|
3. pg_hba.conf에서 인증 방식 확인
|
||||||
|
|
||||||
|
### 포트 8065 접근 불가
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 방화벽 포트 열기
|
||||||
|
sudo firewall-cmd --permanent --add-port=8065/tcp
|
||||||
|
sudo firewall-cmd --reload
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 지원되는 Enterprise 기능
|
||||||
|
|
||||||
|
이 빌드에서 라이선스 없이 사용 가능한 기능:
|
||||||
|
|
||||||
|
- LDAP/AD 연동
|
||||||
|
- SAML SSO
|
||||||
|
- 고가용성 클러스터링
|
||||||
|
- Prometheus 메트릭
|
||||||
|
- 커스텀 권한 스키마
|
||||||
|
- 데이터 보존 정책
|
||||||
|
- 컴플라이언스 내보내기
|
||||||
|
- 메시지 내보내기
|
||||||
|
|
||||||
|
자세한 내용은 `Extend-Function.md`와 `Unlock-License.md`를 참조하세요.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 라이선스
|
||||||
|
|
||||||
|
이 프로젝트는 교육 및 개인 사용 목적으로 제공됩니다.
|
||||||
|
상용 환경에서는 Mattermost 공식 라이선스 구매를 권장합니다.
|
||||||
539
Unlock-License.md
Normal file
539
Unlock-License.md
Normal file
@ -0,0 +1,539 @@
|
|||||||
|
# Mattermost License Unlock Guide
|
||||||
|
|
||||||
|
이 문서는 Mattermost Team Edition에서 Enterprise 기능을 라이선스 없이 사용할 수 있도록 수정한 내용을 상세히 설명합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 개요
|
||||||
|
|
||||||
|
Mattermost Enterprise 기능은 두 가지 레벨에서 제어됩니다:
|
||||||
|
|
||||||
|
1. **인터페이스 구현체**: Enterprise 기능의 실제 코드 (LDAP, SAML, Cluster 등)
|
||||||
|
2. **API 라이선스 체크**: REST API에서 라이선스 유무 확인
|
||||||
|
|
||||||
|
이 프로젝트는 두 가지를 모두 해결합니다:
|
||||||
|
- Enterprise 구현체를 `enterprise-impl/` 디렉토리에 오픈소스로 제공
|
||||||
|
- API의 라이선스 체크 코드를 제거
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 라이선스 체크 제거 상세
|
||||||
|
|
||||||
|
### 1. LDAP API (channels/api4/ldap.go)
|
||||||
|
|
||||||
|
#### 1.1 syncLdap() - LDAP 동기화
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||||
|
c.Err = model.NewAppError("Api4.syncLdap", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ... 나머지 코드
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func syncLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionCreateLdapSyncJob) {
|
||||||
|
c.SetPermissionError(model.PermissionCreateLdapSyncJob)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ... 나머지 코드
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.2 testLdap() - LDAP 연결 테스트
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func testLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||||
|
c.Err = model.NewAppError("Api4.testLdap", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func testLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionTestLdap) {
|
||||||
|
c.SetPermissionError(model.PermissionTestLdap)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.3 getLdapGroups() - LDAP 그룹 조회
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func getLdapGroups(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAPGroups {
|
||||||
|
c.Err = model.NewAppError("Api4.getLdapGroups", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func getLdapGroups(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadUserManagementGroups) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementGroups)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.4 linkLdapGroup() - LDAP 그룹 연결
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func linkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireRemoteId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAPGroups {
|
||||||
|
c.Err = model.NewAppError("Api4.linkLdapGroup", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func linkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireRemoteId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteUserManagementGroups) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleWriteUserManagementGroups)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.5 unlinkLdapGroup() - LDAP 그룹 연결 해제
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func unlinkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireRemoteId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAPGroups {
|
||||||
|
c.Err = model.NewAppError("Api4.unlinkLdapGroup", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func unlinkLdapGroup(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireRemoteId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteUserManagementGroups) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleWriteUserManagementGroups)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.6 migrateIdLdap() - LDAP ID 마이그레이션
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func migrateIdLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||||
|
c.Err = model.NewAppError("Api4.migrateIdLdap", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func migrateIdLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionManageSystem) {
|
||||||
|
c.SetPermissionError(model.PermissionManageSystem)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 1.7 createLdapPublicCertificate() - LDAP 인증서 생성
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func createLdapPublicCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||||
|
c.Err = model.NewAppError("Api4.createLdapPublicCertificate", "api.ldap.license.error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func createLdapPublicCertificate(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteAuthenticationLdap) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleWriteAuthenticationLdap)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. Scheme API (channels/api4/scheme.go)
|
||||||
|
|
||||||
|
커스텀 권한 스키마 기능의 라이선스 체크를 제거했습니다.
|
||||||
|
|
||||||
|
#### 2.1 createScheme() - 스키마 생성
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func createScheme(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.CustomPermissionsSchemes {
|
||||||
|
c.Err = model.NewAppError("Api4.CreateScheme", "api.scheme.create_scheme.license.error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func createScheme(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteUserManagementPermissions) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleWriteUserManagementPermissions)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.2 patchScheme() - 스키마 수정
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func patchScheme(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.CustomPermissionsSchemes {
|
||||||
|
c.Err = model.NewAppError("Api4.PatchScheme", "api.scheme.patch_scheme.license.error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func patchScheme(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
// ...
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteUserManagementPermissions) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleWriteUserManagementPermissions)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2.3 deleteScheme() - 스키마 삭제
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func deleteScheme(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.CustomPermissionsSchemes {
|
||||||
|
c.Err = model.NewAppError("Api4.DeleteScheme", "api.scheme.delete_scheme.license.error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func deleteScheme(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleWriteUserManagementPermissions) {
|
||||||
|
c.SetPermissionError(model.PermissionSysconsoleWriteUserManagementPermissions)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 3. Group API (channels/api4/group.go)
|
||||||
|
|
||||||
|
팀/채널 그룹 기능의 라이선스 체크를 제거했습니다.
|
||||||
|
|
||||||
|
#### 3.1 getGroupsByTeamCommon() - 팀별 그룹 조회
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func getGroupsByTeamCommon(c *Context, r *http.Request) ([]byte, *model.AppError) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAPGroups {
|
||||||
|
return nil, model.NewAppError("Api4.getGroupsByTeam", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func getGroupsByTeamCommon(c *Context, r *http.Request) ([]byte, *model.AppError) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToTeam(*c.AppContext.Session(), c.Params.TeamId, model.PermissionViewTeam) {
|
||||||
|
return nil, c.App.MakePermissionError(c.AppContext.Session(), []*model.Permission{model.PermissionViewTeam})
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2 getGroupsByChannelCommon() - 채널별 그룹 조회
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func getGroupsByChannelCommon(c *Context, r *http.Request) ([]byte, *model.AppError) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAPGroups {
|
||||||
|
return nil, model.NewAppError("Api4.getGroupsByChannel", "api.ldap_groups.license_error", nil, "", http.StatusForbidden)
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func getGroupsByChannelCommon(c *Context, r *http.Request) ([]byte, *model.AppError) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
// Permission check follows...
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 4. User API (channels/api4/user.go)
|
||||||
|
|
||||||
|
사용자 인증 마이그레이션의 라이선스 체크를 제거했습니다.
|
||||||
|
|
||||||
|
#### 4.1 migrateAuthToLdap() - LDAP 인증 마이그레이션
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func migrateAuthToLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||||
|
c.Err = model.NewAppError("Api4.migrateAuthToLdap", "api.user.migrate_auth.license.app_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func migrateAuthToLdap(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
// Email auth in Mattermost system is represented by ""
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 4.2 migrateAuthToSaml() - SAML 인증 마이그레이션
|
||||||
|
|
||||||
|
**원본 코드:**
|
||||||
|
```go
|
||||||
|
func migrateAuthToSaml(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.SAML {
|
||||||
|
c.Err = model.NewAppError("Api4.migrateAuthToSaml", "api.user.migrate_auth.license.app_error", nil, "", http.StatusForbidden)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**수정 후:**
|
||||||
|
```go
|
||||||
|
func migrateAuthToSaml(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
// ...
|
||||||
|
// Community Enterprise: License check removed for open source usage
|
||||||
|
|
||||||
|
if from == "email" {
|
||||||
|
from = ""
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 5. Metrics (channels/app/platform/metrics.go)
|
||||||
|
|
||||||
|
Prometheus 메트릭 엔드포인트가 404를 반환하던 문제를 수정했습니다.
|
||||||
|
|
||||||
|
**추가된 인터페이스:**
|
||||||
|
```go
|
||||||
|
// MetricsHandlerProvider is an interface for metrics implementations that can provide an HTTP handler
|
||||||
|
type MetricsHandlerProvider interface {
|
||||||
|
Handler() http.Handler
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**initMetricsRouter()에 추가된 코드:**
|
||||||
|
```go
|
||||||
|
// Register /metrics handler if metrics implementation provides a handler
|
||||||
|
if pm.metricsImpl != nil {
|
||||||
|
if handlerProvider, ok := pm.metricsImpl.(MetricsHandlerProvider); ok {
|
||||||
|
pm.router.Handle("/metrics", handlerProvider.Handler())
|
||||||
|
pm.logger.Info("Metrics endpoint registered at /metrics")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 라이선스 체크 패턴
|
||||||
|
|
||||||
|
Mattermost 코드에서 라이선스 체크는 일반적으로 다음 패턴을 따릅니다:
|
||||||
|
|
||||||
|
```go
|
||||||
|
// 패턴 1: 단순 nil 체크
|
||||||
|
if c.App.Channels().License() == nil {
|
||||||
|
c.Err = model.NewAppError(...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 2: nil 체크 + 기능 플래그
|
||||||
|
if c.App.Channels().License() == nil || !*c.App.Channels().License().Features.LDAP {
|
||||||
|
c.Err = model.NewAppError(...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 패턴 3: 기능 플래그만 체크
|
||||||
|
if !*c.App.Channels().License().Features.CustomPermissionsSchemes {
|
||||||
|
c.Err = model.NewAppError(...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 제거 방법
|
||||||
|
|
||||||
|
1. 라이선스 체크 조건문 전체를 삭제
|
||||||
|
2. 주석으로 표시: `// Community Enterprise: License check removed for open source usage`
|
||||||
|
3. 권한 체크만 남김 (보안 유지)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 추가 라이선스 체크 위치
|
||||||
|
|
||||||
|
다른 Enterprise 기능에도 라이선스 체크가 있을 수 있습니다. 찾는 방법:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 모든 라이선스 체크 찾기
|
||||||
|
grep -r "License()" channels/api4/ | grep -v "_test.go"
|
||||||
|
|
||||||
|
# 특정 기능의 라이선스 체크
|
||||||
|
grep -r "Features.SAML" channels/api4/
|
||||||
|
grep -r "Features.Cluster" channels/api4/
|
||||||
|
grep -r "Features.Compliance" channels/api4/
|
||||||
|
grep -r "Features.DataRetention" channels/api4/
|
||||||
|
grep -r "Features.MessageExport" channels/api4/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## UI 라이선스 체크
|
||||||
|
|
||||||
|
웹 클라이언트(React)에도 라이선스 체크가 있습니다:
|
||||||
|
|
||||||
|
```
|
||||||
|
client/
|
||||||
|
├── *.js # Minified JavaScript
|
||||||
|
└── *.js.map # Source maps
|
||||||
|
```
|
||||||
|
|
||||||
|
JavaScript 파일은 minified 상태라 직접 수정이 어렵습니다.
|
||||||
|
|
||||||
|
### 해결 방법 옵션
|
||||||
|
|
||||||
|
1. **webapp 소스 빌드**: mattermost/mattermost-webapp 저장소에서 소스를 수정하고 다시 빌드
|
||||||
|
2. **API만 사용**: API는 라이선스 체크가 제거되었으므로 CLI나 API 호출로 기능 사용
|
||||||
|
3. **커스텀 플러그인**: 웹 UI를 우회하는 플러그인 개발
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 면책 조항
|
||||||
|
|
||||||
|
이 수정은 교육 및 개인 학습 목적으로 제공됩니다. 상용 환경에서는 Mattermost 공식 라이선스를 구매하시기 바랍니다.
|
||||||
|
|
||||||
|
Enterprise 기능의 전체 지원과 업데이트를 받으려면 공식 라이선스가 필요합니다.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 참고 자료
|
||||||
|
|
||||||
|
- [Mattermost 공식 문서](https://docs.mattermost.com/)
|
||||||
|
- [Mattermost GitHub](https://github.com/mattermost/mattermost)
|
||||||
|
- [einterfaces 정의](https://github.com/mattermost/mattermost/tree/master/server/channels/einterfaces)
|
||||||
Loading…
Reference in New Issue
Block a user