Skip to content

Commit

Permalink
feat: prevent updating operator ID when subscribers exist (#396)
Browse files Browse the repository at this point in the history
Signed-off-by: guillaume <[email protected]>
  • Loading branch information
gruyaume authored Jan 29, 2025
1 parent a6b7406 commit 7631e0a
Show file tree
Hide file tree
Showing 27 changed files with 1,337 additions and 704 deletions.
36 changes: 35 additions & 1 deletion cmd/core/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
package main

import (
"crypto/rand"
"encoding/hex"
"flag"
"fmt"
"log"
Expand All @@ -22,6 +24,13 @@ import (
"go.uber.org/zap/zapcore"
)

const (
InitialMcc = "001"
InitialMnc = "01"
InitialOperatorSst = 1
InitialOperatorSd = 1056816
)

func startNetwork(dbInstance *db.Database, cfg config.Config) error {
err := nms.Start(dbInstance, cfg.Interfaces.API.Port, cfg.Interfaces.API.TLS.Cert, cfg.Interfaces.API.TLS.Key)
if err != nil {
Expand Down Expand Up @@ -71,7 +80,23 @@ func main() {
log.Fatalf("failed to parse log level: %v", err)
}
logger.SetLogLevel(level)
dbInstance, err := db.NewDatabase(cfg.DB.Path)
initialOp, err := generateOperatorCode()
if err != nil {
log.Fatalf("Failed to generate operator code: %v", err)
}
initialOperatorValues := db.Operator{
Mcc: InitialMcc,
Mnc: InitialMnc,
OperatorCode: initialOp,
Sst: InitialOperatorSst,
Sd: InitialOperatorSd,
}
initialOperatorValues.SetSupportedTacs(
[]string{
"001",
},
)
dbInstance, err := db.NewDatabase(cfg.DB.Path, initialOperatorValues)
if err != nil {
log.Fatalf("Failed to initialize database: %v", err)
}
Expand All @@ -88,3 +113,12 @@ func main() {
logger.EllaLog.Infof("Ella is running")
select {}
}

func generateOperatorCode() (string, error) {
var op [16]byte
_, err := rand.Read(op[:])
if err != nil {
return "", err
}
return hex.EncodeToString(op[:]), nil
}
154 changes: 138 additions & 16 deletions docs/reference/api/operator.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,77 @@
---
description: RESTful API reference for managing the Operator ID and Operator Code.
description: RESTful API reference for managing the Operator Information - ID, Slice, Tracking, and Code.
---

# Operator

## Update the Operator Information
The Operator API provides endpoints to manage the Operator Information used to identify the operator - Operator ID (MCC, MNC), Slice Information (SST, SD), Tracking Information, and Operator Code (OP).

This path updates the operator information. The Mobile Country Code (MCC) and Mobile Network Code (MNC) are used to identify the operator.
## Get Operator Information

This path returns the complete operator information. This includes the Operator ID, Slice Information, and Tracking Information. The Operator Code is never returned.

| Method | Path |
| ------ | ------------------ |
| PUT | `/api/v1/operator` |
| GET | `/api/v1/operator` |

### Parameters

None

### Sample Response

```json
{
"result": {
"id": {
"mcc": "001",
"mnc": "01"
},
"slice": {
"sst": 1,
"sd": 1056816
},
"tracking": {
"supportedTACs": [
"001",
"002",
"003"
]
}
}
}
```

## Update the Operator ID

This path updates the operator ID. The Mobile Country Code (MCC) and Mobile Network Code (MNC) are used to identify the operator. The operator ID can't be changed when there are subscribers created in the system.

| Method | Path |
| ------ | --------------------- |
| PUT | `/api/v1/operator/id` |

### Parameters

- `mcc` (string): The Mobile Country Code (MCC) of the network. Must be a 3-digit string.
- `mnc` (string): The Mobile Network Code (MNC) of the network. Must be a 2 or 3-digit string.
- `supportedTACs` (array): An array of supported TACs (Tracking Area Codes). Each TAC must be a 3-digit string.
- `sst` (integer): The Slice Service Type (SST) of the network. Must be an 8-bit integer
- `sd` (integer): The Service Differentiator (SD) of the network. Must be a 24-bit integer.

### Sample Response

```json
{
"result": {
"message": "Operator updated successfully"
"message": "Operator ID updated successfully"
}
}
```

## Get Operator Information
## Get Operator ID

This path returns the operator Information.
This path returns the operator ID.

| Method | Path |
| ------ | ------------------ |
| GET | `/api/v1/operator` |
| Method | Path |
| ------ | --------------------- |
| GET | `/api/v1/operator/id` |

### Parameters

Expand All @@ -49,20 +84,107 @@ None
"result": {
"mcc": "001",
"mnc": "01",
}
}
```

## Update the Operator Slice Information

This path updates the operator slice information. Only one slice is supported. The Slice Service Type (SST) and Service Differentiator (SD) are used to identify the slice.

| Method | Path |
| ------ | ------------------------ |
| PUT | `/api/v1/operator/slice` |

### Parameters

- `sst` (integer): The Slice Service Type (SST) of the network. Must be an 8-bit integer.
- `sd` (integer): The Service Differentiator (SD) of the network. Must be a 24-bit integer.

### Sample Response

```json
{
"result": {
"message": "Operator slice information updated successfully"
}
}
```

## Get Operator Slice Information

This path returns the operator Slice Information.

| Method | Path |
| ------ | ------------------------ |
| GET | `/api/v1/operator/slice` |

### Parameters

None

### Sample Response

```json
{
"result": {
"sst": 1,
"sd": 1056816
}
}
```

## Update the Operator Tracking Information

This path updates the operator tracking information. The Tracking Area Codes (TACs) are used to identify the tracking areas supported by the operator. 5G radios will need to be configured with one or more of these TACs to connect to the network.

| Method | Path |
| ------ | --------------------------- |
| PUT | `/api/v1/operator/tracking` |

### Parameters

- `supportedTACs` (array): An array of supported TACs (Tracking Area Codes). Each TAC must be a 24-bit integer.

### Sample Response

```json
{
"result": {
"message": "Operator tracking information updated successfully"
}
}
```

## Get Operator Tracking Information

This path returns the operator Tracking Information.

| Method | Path |
| ------ | --------------------------- |
| GET | `/api/v1/operator/tracking` |

### Parameters

None

### Sample Response

```json
{
"result": {
"supportedTACs": [
"001",
"002",
"003"
],
"sst": 1,
"sd": 1056816
}
}
```

## Update the Operator Code (OP)

This path updates the Operator Code (OP). The OP is a 32-character hexadecimal string that identifies the operator. This value is secret and should be kept confidential. The OP is used to create the derived Operator Code (OPc).
This path updates the Operator Code (OP). The OP is a 32-character hexadecimal string that identifies the operator. This value is secret and should be kept confidential. The OP is used to create the derived Operator Code (OPc). The OP can't be changed when there are subscribers created in the system.

| Method | Path |
| ------ | ----------------------- |
Expand Down
8 changes: 2 additions & 6 deletions internal/db/backup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestDatabaseBackup(t *testing.T) {
tempDir := t.TempDir()

dbPath := filepath.Join(tempDir, "db.sqlite3")
database, err := db.NewDatabase(dbPath)
database, err := db.NewDatabase(dbPath, initialOperator)
if err != nil {
t.Fatalf("Couldn't initialize NewDatabase: %s", err)
}
Expand All @@ -24,11 +24,7 @@ func TestDatabaseBackup(t *testing.T) {
}
}()

operator := &db.Operator{
Mcc: "123",
Mnc: "456",
}
err = database.UpdateOperator(operator)
err = database.UpdateOperatorId("123", "456")
if err != nil {
t.Fatalf("Couldn't update operator id: %s", err)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (db *Database) Close() error {
// stores the connection information and returns an object containing the information.
// The database path must be a valid file path or ":memory:".
// The table will be created if it doesn't exist in the format expected by the package.
func NewDatabase(databasePath string) (*Database, error) {
func NewDatabase(databasePath string, initialOperator Operator) (*Database, error) {
sqlConnection, err := sql.Open("sqlite3", databasePath)
if err != nil {
return nil, err
Expand Down Expand Up @@ -66,7 +66,7 @@ func NewDatabase(databasePath string) (*Database, error) {
db.operatorTable = OperatorTableName
db.radiosTable = RadiosTableName
db.usersTable = UsersTableName
err = db.InitializeOperator()
err = db.InitializeOperator(initialOperator)
if err != nil {
return nil, fmt.Errorf("failed to initialize network configuration: %v", err)
}
Expand Down
11 changes: 10 additions & 1 deletion internal/db/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,18 @@ import (
"github.com/ellanetworks/core/internal/db"
)

var initialOperator = db.Operator{
Mcc: "001",
Mnc: "01",
OperatorCode: "0123456789ABCDEF0123456789ABCDEF",
Sst: 1,
Sd: 1056816,
SupportedTACs: `["001"]`,
}

func TestConnect(t *testing.T) {
tempDir := t.TempDir()
db, err := db.NewDatabase(filepath.Join(tempDir, "db.sqlite3"))
db, err := db.NewDatabase(filepath.Join(tempDir, "db.sqlite3"), initialOperator)
if err != nil {
t.Fatalf("Can't connect to SQLite: %s", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/db/metrics_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestDatabaseMetrics(t *testing.T) {
tempDir := t.TempDir()
dbPath := filepath.Join(tempDir, "db.sqlite3")

database, err := db.NewDatabase(dbPath)
database, err := db.NewDatabase(dbPath, initialOperator)
if err != nil {
t.Fatalf("Couldn't initialize NewDatabase: %s", err)
}
Expand Down
Loading

0 comments on commit 7631e0a

Please sign in to comment.