SIM卡配置
OmniCRM为移动网络运营商和虚拟移动网络运营商(MVNO)提供全面的物理SIM卡和eSIM(嵌入式SIM)配置支持。该系统处理从库存管理到激活、分配和取消配置的完整生命周期。
另请参阅:配置系统以了解一般配置概念,库存以了解库存管理,Ansible剧本以了解配置自动化。
概述
OmniCRM中的SIM配置涉及多个集成系统共同工作:
- 库存管理 - 跟踪可用的SIM卡(物理和eSIM配置文件)
- HSS/IMS集成 - 配置用户凭据和语音服务
- OCS集成 - 设置服务的计费和收费
- Ansible自动化 - 协调配置工作流
- 自助注册支持 - 使客户能够激活自己的SIM卡
物理SIM卡配置
物理SIM卡是客户插入其设备的传统可拆卸SIM卡。OmniCRM通过库存系统管理这些SIM卡,并将其配置到HSS/IMS以获得网络访问。
物理SIM工作流
1. 库存设置
SIM卡必须首先加载到库存系统中:
- ICCID(集成电路卡标识符) - 唯一的SIM卡标识符
- IMSI(国际移动用户身份) - 网络的用户身份
这些信息存储在库存项目字段中:
itemtext1: ICCIDitemtext2: IMSIitemtext3: SIM类型(物理/eSIM) - 可选
示例物理SIM库存项目:
{
"inventory_id": 1001,
"item": "SIM Card",
"itemtext1": "8961234567890123456", // ICCID
"itemtext2": "310120123456789", // IMSI
"itemtext3": "Physical", // SIM Type
"item_location": "Warehouse A, Shelf 3",
"item_state": "New",
"wholesale_cost": 2.50,
"retail_cost": 10.00
}
有关所有库存字段(itemtext1-20、item_state值、地址字段、management_url等)的完整说明,请参见库存概述 - 库存项目字段。
身份验证凭据存储
SIM卡的身份验证凭据存储在**HSS AuC(认证中心)**中,而不是CRM库存中:
- Ki(认证密钥) - 用于认证的密钥(存储在HSS中)
- OPC(运营商代码) - 运营商特定的认证参数(存储在HSS中)
- PIN1/PIN2 - 用户PIN码(存储在HSS中)
- PUK1/PUK2 - PIN解锁码(存储在HSS中)
CRM库存跟踪哪个SIM(通过ICCID/IMSI)分配给哪个客户,而HSS使用与物理SIM卡匹配的Ki/OPC凭据处理实际的网络认证。
2. 服务分配
当客户订购移动服务时:
- 员工或客户从库存中选择一个可用的SIM卡
- 从电话号码库存中选择一个手机号码(MSISDN)
- 触发产品的配置剧本(例如,
play_psim_only.yaml)
3. HSS配置
Ansible剧本将用户配置到家庭用户服务器(HSS):
首先,它检索auc_id(对已经存储在HSS中的认证凭据的引用):
- name: Get AuC ID for IMSI
uri:
url: "{{ item }}/auc/imsi/{{ imsi }}"
method: GET
loop: "{{ hss_peers }}"
register: auc_lookup
- name: Extract auc_id
set_fact:
auc_id: "{{ auc_lookup.results[0].json.auc_id }}"
然后创建引用该auc_id的用户记录:
- name: Provision subscriber on HSS
uri:
url: "{{ item }}/subscriber/"
method: PUT
body_format: json
body:
enabled: true
roaming_enabled: true
auc_id: "{{ auc_id }}"
msisdn: "{{ phone_number }}"
imsi: "{{ imsi }}"
ue_ambr_dl: 9999999
ue_ambr_ul: 9999999
apn_list: "1,2,3"
default_apn: 1
loop: "{{ hss_peers }}"
身份验证凭据(Ki、OPC)保留在HSS AuC中,永远不会暴露给CRM或配置剧本。
4. IMS配置(用于语音服务)
为了实现语音通话能力,创建IMS用户:
- name: Create IMS subscriber for voice services
uri:
url: "{{ item }}/ims_subscriber/"
method: PUT
body_format: json
body:
imsi: "{{ imsi }}"
msisdn: "{{ phone_number }}"
msisdn_list: "{{ phone_number }}"
ifc_path: "default_ifc.xml"
sh_profile: "{{ sh_profile_xml }}"
loop: "{{ hss_peers }}"
5. 计费系统设置
OCS(在线计费系统)配置为:
- 创建账户
- 通过属性���置文件进行IMSI/MSISDN映射
- 识别用户的过滤规则
- 资源限制(并发会话)
- 初始余额
6. 服务创建和库存分配
最后:
- 在CRM中创建服务记录
- 将SIM卡库存项目分配给客户(
customer_id设置) - 将SIM卡链接到服务(
service_id设置) - 更新库存状态为“已分配”
物理SIM身份验证
物理SIM使用存储在HSS中的AuC(认证中心)凭据:
- Ki和OPC用于4G/5G认证(MILENAGE算法)
- 这些凭据在SIM导入期间预加载到HSS AuC数据库中
- 物理SIM卡包含匹配的Ki/OPC值
- 在配置期间,剧本引用auc_id以将用户与这些凭据链接
- 网络认证通过SIM和HSS之间的挑战-响应进行
- CRM从未看到或处理实际的Ki/OPC值
eSIM配置
eSIM(嵌入式SIM)是可以下载到兼容设备的软件基础SIM配置文件,无需物理SIM卡。OmniCRM支持使用LPA(本地配置助手)激活代码进行eSIM配置。
eSIM功能
LPA激活代码
eSIM使用LPA代码进行激活:
LPA:1$smdp.example.com$ACTIVATION-CODE-ABC123XYZ
其中:
LPA:1- LPA版本标识符smdp.example.com- SM-DP+(订阅管理数据准备)服务器地址ACTIVATION-CODE-ABC123XYZ- 此eSIM配置文件的唯一激活代码
二维码生成
OmniCRM自动从LPA激活代码生成二维码:
- 存储在库存
management_url字段中 - 在用户界面中显示为可扫描的二维码
- 客户使用设备相机扫描以安装eSIM配置文件
- 无需手动输入长激活代码
示例eSIM库存项目:
{
"inventory_id": 1002,
"item": "eSIM",
"itemtext1": "8961234567890123457",
"itemtext2": "310120123456790",
"itemtext3": "eSIM",
"management_url": "LPA:1$smdp.example.com$ACTIVATION-CODE-ABC123XYZ",
"item_location": "Virtual Inventory",
"item_state": "New",
"wholesale_cost": 0.00,
"retail_cost": 0.00
}
在用户界面查看此库存项目时,会自动生成并显示二维码以便于扫描。
eSIM配置工作流
eSIM配置工作流与物理SIM配置几乎相同,但有几个关键区别:
1. 自动eSIM分配
如果产品需要SIM但未选择物理SIM,系统可以自动分配一个可用的eSIM:
# 自动eSIM查找
search_filters = {
"customer_id": [None],
"item_state": ["New"],
"itemtext3": ["eSIM"] # 过滤eSIM类型
}
available_esim = search_inventory("SIM Card", filters=search_filters)
2. HSS/IMS配置
eSIM与物理SIM的配置方式完全相同:
- 相同的IMSI配置
- 相同的IMS用户创建
- ��同的身份验证凭据(Ki、OPC)
3. 客户激活
配置后:
- 客户通过电子邮件或客户门户接收eSIM激活详细信息
- 显示二维码以供扫描
- 客户使用设备扫描二维码
- 设备从SM-DP+服务器下载eSIM配置文件
- eSIM安装并准备使用
公共eSIM发行者API
OmniCRM提供一个公共API端点以支持自助eSIM请求,使客户能够直接从网站或移动应用请求eSIM,而无需工作人员干预。
端点: POST /crm/oam/issue-esim
请求参数
| 参数 | 类型 | 必需 | 默认 | 描述 |
|---|---|---|---|---|
email | 字符串 | 是 | - | 客户电子邮件地址,用于eSIM交付。必须是有效的电子邮件格式。 |
name | 字符串 | 否 | 从电子邮件派生 | 客户名称,用于电子邮件个性化。如果未提供,则使用电子邮件地址的本地部分。 |
customer_id | 整数 | 否 | null | 现有客户ID。当提供时,创建与客户关联的活动记录以进行跟踪。 |
device_info | 对象 | 否 | {} | 设备信息,用于分析和兼容性跟踪。 |
device_info.compatibility_status | 字符串 | 否 | "unknown" | eSIM兼容性状态:supported、may-support或unknown。用于分析。 |
device_info.user_agent | 字符串 | 否 | 请求头 | 用户代理字符串。如果未提供,则从请求头自动捕获。 |
速率限制
该端点实现双重速率限制以防止滥用:
| 限制 | 窗口 | 范围 | 描述 |
|---|---|---|---|
| 10请求 | 1分钟 | 每个IP地址 | 通过装饰器应用的一般速率限制 |
| 3请求 | 24小时 | 每个电子邮件地址 | 防止向同一电子邮件发送过多eSIM请求 |
当超过速率限制时,端点返回HTTP 429,带有error_type: "RateLimitExceeded"。
响应格式
成功响应(HTTP 200):
{
"result": "Success",
"message": "eSIM request received. You will receive your eSIM QR code via email shortly.",
"esim_id": 8472,
"iccid": "8944200000001234567",
"email_sent": true
}
| 字段 | 类型 | 描述 |
|---|---|---|
result | 字符串 | 对于HTTP 200响应始终为"Success" |
message | 字符串 | 可读的确认消息 |
esim_id | 整数 | 分配的eSIM的库存ID |
iccid | 字符串 | 分配的eSIM的ICCID |
email_sent | 布尔值 | 交付电子邮件是否成功发送 |
错误响应
| HTTP代码 | 错误类型 | 描述 |
|---|---|---|
| 400 | - | 无效或缺失的电子邮件地址 |
| 429 | RateLimitExceeded | 每个电子邮件或每个IP的速率限制超出 |
| 503 | NoInventory | 库存中没有可用的eSIM |
| 500 | - | 服务器内部错误 |
错误响应格式:
{
"result": "Failed",
"reason": "Error description",
"error_type": "ErrorType"
}
电子邮件交付
该端点通过Mailjet发送包含以下内容的eSIM交付电子邮件:
- ICCID
- 二维码(如果在
itemtext2中可用) - 激活代码/LPA字符串(如果在
itemtext3或management_url中可用) - 步骤激活说明
在crm_config.yaml中配置Mailjet模板:
mailjet:
api_crmCommunicationEsimDelivery:
from_email: "support@aimobile.ac"
from_name: "Ascension Island Mobile"
template_id: 1234567
subject: "Your eSIM is Ready"
| 参数 | 类型 | 必需 | 描述 |
|---|---|---|---|
from_email | 字符串 | 是 | 发件人电子邮件地址 |
from_name | 字符串 | 是 | 发件人显示名称 |
template_id | 整数 | 否 | Mailjet模板ID。如果未提供,则生成默认HTML电子邮件。 |
subject | 字符串 | 是 | 电子邮件主题行 |
如果未配置模板,系统将生成带有以下内容的品牌HTML电子邮件:
- 公司品牌和徽标
- eSIM激活的二维码(如果可用)
- 手动激活代码说明
- 针对iOS和Android的设备特定设置指南
活动日志记录
每个eSIM请求都会创建一个活动记录,包含:
- 活动类型:
esim_request - 客户ID链接(如果提供)
- 设备兼容性状态
- 用户代理信息
这使得跟踪eSIM请求和转化分析成为可能。
4. HSS中的eSIM数据结构
HSS AuC(认证中心)中的eSIM标记为esim: true标志:
{
"esim": true,
"lpa": "LPA:1$smdp.example.com$ACTIVATION-CODE-ABC123XYZ",
"iccid": "8961234567890123457",
"imsi": "310120123456790",
"ki": "00112233445566778899AABBCCDDEEFF",
"opc": "FFEEDDCCBBAA99887766554433221100",
"pin1": "1234",
"pin2": "5678",
"puk1": "12345678",
"puk2": "87654321",
"batch_name": "eSIM_Batch_2024_Q1",
"sim_vendor": "Thales"
}
eSIM导入过程
eSIM通常从eSIM供应商批量导入:
导入脚本: /OmniCRM-API/Provisioners/customer_product_creation/import_keys_esim.py
导入过程:
- 从供应商提供的Excel文件中读取eSIM数据
- 从CSV文件中加载LPA激活代码
- 更新HSS以包含eSIM凭据
- 在CRM中创建相应的库存项目
- 将eSIM配置文件链接到库存系统
这确保eSIM配置文件在保持适当库存跟踪的同时可用于分配。
库存集成
库存系统是SIM配置的核心,跟踪移动服务所需的物理和虚拟资源。
SIM卡库存模板
典型的SIM卡库存模板定义:
{
"item": "SIM Card",
"itemtext1_label": "ICCID",
"itemtext2_label": "IMSI",
"itemtext3_label": "SIM Type",
"wholesale_cost": 2.50,
"retail_cost": 10.00
}
注意:身份验证凭据(Ki、OPC、PIN、PUK)存储在HSS AuC中,而不是在CRM库存中。
有关创建和管理库存模板的详细信息,包括如何定义自定义字段(itemtext1-20)和将模板链接到产品,请参见库存管理 - 库存模板部分。
手机号码库存
电话号码作为单独的库存���目进行管理:
{
"inventory_id": 4001,
"item": "Mobile Number",
"itemtext1": "+61412345678",
"itemtext2": "Melbourne",
"itemtext3": "Mobile",
"item_location": "Australia - VIC",
"item_state": "New",
"wholesale_cost": 1.00,
"retail_cost": 0.00
}
SIM的库存状态
SIM卡经历多个库存状态:
- 新 - 未使用的SIM,可供分配
- 已分配 - 当前与客户活跃
- 已使用 - 以前分配,返回库存(可以重复使用)
- 内部使用 - 用于测试或员工使用
- 损坏 - 无法使用,需要更换
- 丢失 - 无法找到
- 被盗 - 报告被盗
产品集成
产品通过inventory_items_list指定所需库存:
{
"product_id": 1,
"product_slug": "Mobile-SIM",
"product_name": "Mobile SIM Only",
"provisioning_play": "play_psim_only",
"inventory_items_list": "['SIM Card', 'Mobile Number']"
}
在配置此产品时:
- 用户界面显示库存选择器,带有两个下拉菜单
- 用户选择可用的SIM卡(物理或eSIM)
- 用户选择可用的手机号码
- 库存ID传递给Ansible剧本
- 剧本通过API检索完整的库存详细信息
- 配置继续使用所选资源
有关产品如何驱动配置、如何定义库存要求以及如何将变量传递给剧本的完整说明,请参见配置系统 - 产品如何驱动配置。
库存分配流程
Ansible剧本处理库存分配。
有关剧本如何使用CRM API进行身份验证(Bearer令牌、API密钥、刷新令牌)的更多详细信息,请参见配置系统 - 身份验证和授权。
- name: Get SIM Card details from inventory
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ inventory_id_sim_card }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: sim_inventory_response
- name: Extract SIM identifiers
set_fact:
iccid: "{{ sim_inventory_response.json.itemtext1 }}"
imsi: "{{ sim_inventory_response.json.itemtext2 }}"
- name: Get AuC ID from HSS (reference to authentication credentials)
uri:
url: "{{ item }}/auc/imsi/{{ imsi }}"
method: GET
loop: "{{ hss_peers }}"
register: auc_response
- name: Extract AuC ID
set_fact:
auc_id: "{{ auc_response.results[0].json.auc_id }}"
# ... provision to HSS/IMS/OCS ...
- name: Assign SIM to customer
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ inventory_id_sim_card }}"
method: PATCH
headers:
Authorization: "Bearer {{ access_token }}"
body_format: json
body:
customer_id: "{{ customer_id }}"
service_id: "{{ service_id }}"
item_state: "Assigned"
这确保:
- SIM标记为分配给客户
- 服务ID链接以进行跟踪
- 库存状态反映当前状态
- 其他系统可以查询库存以查找客户的SIM
自助注册与SIM配置
OmniCRM支持客户自助注册,客户可以在没有工作人员干预的情况下激活自己的SIM卡或eSIM。
自助注册流程
1. 客户启动注册
客户访问自助注册页面并开始创建账户:
- 提供个人信息
- 选择服务计划(产品)
- 输入支付详情
2. SIM号码验证
客户可以提供自己的SIM号码(可选):
GET /auth/self-signup/validate-itemtext1/{sim_number}
该端点检查:
- SIM是否存在于库存中
- SIM是否可用(未分配)
- SIM是否处于正确状态(“新”或“已使用”)
3. 自动SIM分配(如果未提供SIM)
如果客户没有SIM,系统将自动分配一个:
def _populate_base_plan_inventory(sim_number, plan):
if sim_number:
# 客户提供的SIM - 验证其存在
sim_inventory = get_inventory_by_itemtext1(session, sim_number, None)
if not sim_inventory:
# 检查是否有与此号码相关的非活动服务
service = get_inactive_service_by_sim(sim_number)
if service:
sim_inventory = get_sim_for_service(service.service_id)
else:
# 从库存中自动分配可用的SIM
sim_inventory = get_first_available_inventory_by_item_name(
session,
"SIM Card",
filters={"item_state": ["New"], "customer_id": [None]}
)
# 获取ICCID和MSISDN
iccid = sim_inventory.itemtext1
# 自动分配电话号码
number_inventory = get_first_available_inventory_by_item_name(
session,
"Mobile Number"
)
msisdn = number_inventory.itemtext1
return {
"SIM Card": sim_inventory.inventory_id,
"Mobile Number": number_inventory.inventory_id
}
4. 账户创建和配置
一旦支付获得授权:
def _post_signup_tasks(customer_id, plan, payment_method):
# 1. 保存支付方式
save_stripe_payment_method(customer_id, payment_method)
# 2. 向客户卡收费
charge_customer_card(customer_id, plan.retail_setup_cost)
# 3. 登录用户(获取JWT令牌)
tokens = login_customer(customer_id)
# 4. 填充库存(SIM和电话号码)
inventory_vars = _populate_base_plan_inventory(sim_number, plan)
# 5. 创建配置作业
provision_vars = {
"product_id": plan.product_id,
"customer_id": customer_id,
**inventory_vars # 包括SIM卡和手机号码ID
}
# 可选:链接附加产品
if plan.addon_chain:
provision_vars["addon_chain"] = plan.addon_chain
provision_id = create_provisioning_job(provision_vars)
# 6. 返回成功与令牌
return {
"access_token": tokens.access_token,
"refresh_token": tokens.refresh_token,
"customer_id": customer_id,
"provision_id": provision_id
}
5. 客户接收激活详细信息
配置完成后:
- 物理SIM:欢迎电子邮件,包含电话号码和激活说明
- eSIM:电子邮件包括eSIM配置文件下载的二维码,或客户可以在客户门户中查看二维码
6. 自助注册的特殊权限
在注册期间,JWT令牌包含一个特殊声明:
{
"sub": "customer_123",
"signup_process": true,
"permissions": ["VIEW_OWN_PROVISION", "UPDATE_OWN_INVENTORY"]
}
这允许:
- 客户在注册期间读取/更新库存
- 仅限于他们自己的客户账户
- 防止分配属于其他客户的SIM
自助注册安全性
验证检查:
- SIM必须存在于库存中
- SIM不得分配给其他客户
- SIM必须处于可接受状态(“新”、“已使用”)
- 客户只能将SIM分配给自己的账户
- 在配置之前,必须授权支付
库存保护措施:
- 数据库事务确保原子分配
- 通过数据库锁防止并发注册尝试
- 库存状态更改记录以供审计
基于Ansible的配置
所有SIM配置通过Ansible剧本进行协调,提供一致、可审计和可重复的过程。
有关Ansible剧本结构、块/恢复模式、剧本如何与产品交互以及最佳实践的全面文档,请参见Ansible剧本:详细指南。
主要SIM配置剧本
文件: /OmniCRM-API/Provisioners/plays/play_psim_only.yaml
这是移动SIM配置(物理和eSIM)的主要剧本。它处理:
- 移动语音和数据服务
- 仅数据服务
- 仅语音IMS用户
剧本结构(1,561行):
有关剧本头部、hosts/gather_facts/become指令和整体结构的详细说明,请参见Ansible剧本 - 剧本结构和解剖。
- name: OmniCore Service Provisioning 2024
hosts: localhost
gather_facts: no
become: False
tasks:
- name: Main provisioning block
block:
# --- 预配置(行240-396) ---
- name: Get SIM information from inventory
# Retrieves IMSI, ICCID, etc.
- name: Validate IMSI length
# Must be exactly 15 digits
- name: Check if IMSI exists in HSS
# Prevents duplicate provisioning
- name: Get AuC ID for IMSI
# Retrieves auc_id reference from HSS
# --- HSS配置(行398-534) ---
- name: Create/Update HSS Subscriber
# Provisions to all HSS peers
- name: Create IMS Subscriber
# Enables voice calling
# --- OCS设置(行536-837) ---
- name: Create ENUM entry
# E.164 number mapping
- name: Create FilterS rule
# Account identification
- name: Create AttributeS profile
# IMSI/MSISDN mapping
- name: Create ResourceS profile
# Concurrent session limits
- name: Create OCS account
# Billing account creation
# --- 服务和库存(行865-946) ---
- name: Create service record
# In CRM database
- name: Assign SIM to service
# Update inventory
- name: Send welcome SMS
# Customer notification
rescue:
# --- 清理/取消配置(行975-1562) ---
- name: Return inventory to pool
# Reset customer_id, service_id to null
- name: Delete OCS account
# Remove billing account
- name: Remove HSS subscribers
# Or set to dormant state
- name: Determine success/failure
assert:
that:
- action == "deprovision"
关键配置步骤
1. 预配置验证
- name: Get SIM information from CRM inventory
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ inventory_id_sim_card }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: api_response_sim
- name: Extract and validate IMSI
set_fact:
imsi: "{{ api_response_sim.json.itemtext2 }}"
- name: Validate IMSI format
assert:
that:
- imsi | length == 15
- imsi is match('^[0-9]+$')
fail_msg: "IMSI must be exactly 15 digits"
2. 从HSS检索AuC ID
- name: Get AuC ID for IMSI from HSS
uri:
url: "{{ item }}/auc/imsi/{{ imsi }}"
method: GET
loop: "{{ crm_config.hss.hss_peers }}"
register: auc_lookup
- name: Extract auc_id from first HSS response
set_fact:
auc_id: "{{ auc_lookup.results[0].json.auc_id }}"
3. HSS用户配置
- name: Create subscriber in each HSS peer
uri:
url: "{{ item }}/subscriber/"
method: PUT
body_format: json
body:
enabled: true
roaming_enabled: true
auc_id: "{{ auc_id }}"
msisdn: "{{ phone_number }}"
imsi: "{{ imsi }}"
ue_ambr_dl: 9999999 # 下载速度限制
ue_ambr_ul: 9999999 # 上传速度限制
apn_list: "1,2,3"
default_apn: 1
status_code: [200, 201]
loop: "{{ crm_config.hss.hss_peers }}"
register: hss_responses
4. IMS用户配置(语音)
- name: Create IMS subscriber for voice services
uri:
url: "{{ item }}/ims_subscriber/"
method: PUT
body_format: json
body:
imsi: "{{ imsi }}"
msisdn: "{{ phone_number }}"
msisdn_list: "{{ phone_number }}"
ifc_path: "default_ifc.xml"
sh_profile: |
<?xml version="1.0"?>
<IMSSubscription>
<PrivateID>{{ imsi }}@ims.mnc{{ mnc }}.mcc{{ mcc }}.3gppnetwork.org</PrivateID>
<ServiceProfile>
<PublicIdentity>
<Identity>sip:{{ phone_number }}@ims.mnc{{ mnc }}.mcc{{ mcc }}.3gppnetwork.org</Identity>
</PublicIdentity>
</ServiceProfile>
</IMSSubscription>
status_code: [200, 201]
loop: "{{ crm_config.hss.hss_peers }}"
5. OCS计费配置
# 创建账户过滤器(通过IMSI/MSISDN识别用户)
- name: Create FilterS for IMSI identification
uri:
url: "{{ crm_config.ocs.ocsApi }}/jsonrpc"
method: POST
body_format: json
body:
method: "ApierV1.SetFilter"
params:
- ID: "FILTER_IMSI_{{ service_uuid }}"
Type: "*string"
Element: "~*req.OriginHost"
Values: ["{{ imsi }}"]
# 创建属性配置文件(将IMSI映射到账户)
- name: Create AttributeS profile
uri:
url: "{{ crm_config.ocs.ocsApi }}/jsonrpc"
method: POST
body_format: json
body:
method: "ApierV1.SetAttributeProfile"
params:
- ID: "ATTR_ACCOUNT_{{ service_uuid }}"
FilterIDs: ["FILTER_IMSI_{{ service_uuid }}"]
Attributes:
- Path: "*req.Account"
Value: "{{ service_uuid }}"
# 创建计费账户
- name: Create OCS account
uri:
url: "{{ crm_config.ocs.ocsApi }}/jsonrpc"
method: POST
body_format: json
body:
method: "ApierV2.SetAccount"
params:
- Tenant: "{{ crm_config.ocs.ocsTenant }}"
Account: "{{ service_uuid }}"
ActionPlanIds: []
ExtraOptions:
AllowNegative: false
Disabled: false
# 添加初始余额
- name: Add initial monetary balance
uri:
url: "{{ crm_config.ocs.ocsApi }}/jsonrpc"
method: POST
body_format: json
body:
method: "ApierV1.AddBalance"
params:
- Tenant: "{{ crm_config.ocs.ocsTenant }}"
Account: "{{ service_uuid }}"
BalanceType: "*monetary"
Balance:
Value: 0
ExpiryTime: "+8760h" # 1 year
6. 服务创建
- name: Create service record in CRM
uri:
url: "{{ crm_config.crm.base_url }}/crm/service/"
method: PUT
headers:
Authorization: "Bearer {{ access_token }}"
body_format: json
body:
customer_id: "{{ customer_id }}"
product_id: "{{ product_id }}"
service_name: "Mobile Service - {{ phone_number }}"
service_uuid: "{{ service_uuid }}"
service_status: "Active"
retail_cost: "{{ monthly_cost }}"
status_code: 200
register: service_creation_response
- name: Extract service_id
set_fact:
service_id: "{{ service_creation_response.json.service_id }}"
7. 库存分配
- name: Assign SIM card to customer and service
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ inventory_id_sim_card }}"
method: PATCH
headers:
Authorization: "Bearer {{ access_token }}"
body_format: json
body:
customer_id: "{{ customer_id }}"
service_id: "{{ service_id }}"
item_state: "Assigned"
sold_date: "{{ ansible_date_time.iso8601 }}"
- name: Assign phone number to customer and service
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ inventory_id_phone_number }}"
method: PATCH
headers:
Authorization: "Bearer {{ access_token }}"
body_format: json
body:
customer_id: "{{ customer_id }}"
service_id: "{{ service_id }}"
item_state: "Assigned"
sold_date: "{{ ansible_date_time.iso8601 }}"
取消配置和回滚
同一剧本处理失败的配置回滚和有意的取消配置,使用Ansible的rescue块。
有关块/恢复模式的详细说明以及为什么这是最佳实践,请参见配置系统 - 回滚和清理:最佳实践模式。
rescue:
# 此部分在以下情况下运行:
# 1. 块中的任何任务失败(自动回滚)
# 2. action == "deprovision"(有意清理)
- name: Get inventory items linked to service
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/customer_id/{{ customer_id }}"
method: GET
headers:
Authorization: "Bearer {{ access_token }}"
register: inventory_items
ignore_errors: true
- name: Return inventory to available pool
uri:
url: "{{ crm_config.crm.base_url }}/crm/inventory/inventory_id/{{ item.inventory_id }}"
method: PATCH
headers:
Authorization: "Bearer {{ access_token }}"
body_format: json
body:
customer_id: null
service_id: null
item_state: "Used"
loop: "{{ inventory_items.json.data }}"
when: inventory_items.json.data is defined
ignore_errors: true
- name: Delete OCS account
uri:
url: "{{ crm_config.ocs.ocsApi }}/jsonrpc"
method: POST
body_format: json
body:
method: "ApierV1.RemoveAccount"
params:
- Tenant: "{{ crm_config.ocs.ocsTenant }}"
Account: "{{ service_uuid }}"
ignore_errors: true
- name: Delete or disable HSS subscriber
uri:
url: "{{ item.key }}/subscriber/{{ item.value.subscriber_id }}"
method: DELETE
loop: "{{ hss_subscriber_data | dict2items }}"
when: deprovision_subscriber | default(false) | bool
ignore_errors: true
# 最终断��确定成功或失败
- name: Determine if this was intentional deprovision or failed provision
assert:
that:
- action == "deprovision"
fail_msg: "Provisioning failed and rollback completed"
success_msg: "Deprovisioning completed successfully"
关键点:
- 所有清理任务上的
ignore_errors: true确保所有清理尝试都被执行 - 如果
action == "deprovision",则断言通过(状态0 = 成功) - 如果未设置
action,则断言失败(状态2 = 失败的配置) - 这确保原子操作:要么完全配置,要么完全清理
其他与SIM相关的剧本
本地开发剧本:
play_local_mobile_sim.yaml - 跳过外部HSS/OCS依赖关系的开发版本
MSISDN交换:
play_swap_msisdn.yaml - 在现有服务之间交换电话号码
充值/充值剧本:
play_topup_monetary.yaml- 添加货币余额play_topup_no_charge.yaml- 添加免费数据/分钟play_topup_dongle.yaml- 为物联网/数据设备充值
HSS和IMS集成
OmniCRM与PyHSS(开源家庭用户服务器)集成,以进行用户管理和认证。
HSS功能
文件: /OmniCRM-API/Provisioners/hss.py
关键功能:
def ProvisionMobileSIM(json_data, hss_urls):
"""
Provisions a mobile SIM to HSS and IMS
Args:
json_data: Dict with IMSI, MSISDN, authentication credentials
hss_urls: List of HSS peer URLs
Returns:
Dict with subscriber IDs from each HSS peer
"""
# Create HSS subscriber (for data)
# Create IMS subscriber (for voice)
# Return subscriber IDs for tracking
def get_subscriber_info_msisdn(msisdn, hss_urls):
"""
Retrieves subscriber details by phone number
Args:
msisdn: Phone number to lookup
hss_urls: List of HSS peer URLs
Returns:
Subscriber information from HSS
"""
多HSS支持
OmniCRM支持向多个HSS对等体进行配置以实现冗余:
# crm_config.yaml
hss:
hss_peers:
- "http://10.12.64.140:8080"
- "http://10.12.64.141:8080"
apn_list: "1,2,3"
default_apn: 1
配置在所有配置的HSS实例之间进行,以确保:
- 地理冗余
- 负载均衡
- 故障转移能力
- 同步的用户数据
认证中心(AuC)
AuC存储用户认证凭据。在配置期间,仅检索auc_id:
获取IMSI的AuC ID:
GET /auc/imsi/{imsi}
响应:
{
"auc_id": 12345,
"imsi": "310120123456789",
"iccid": "8961234567890123456",
"esim": false,
"lpa": null
}
对于eSIM,esim标志为true,lpa包含激活代码以供客户显���。
注意: 实际的认证凭据(Ki、OPC、PIN、PUK)保留在HSS中,永远不会通过API暴露。配置系统只需要auc_id来引用这些凭据以创建用户。
OCS集成
在线计费系统(OCS)处理移动服务的实时计费和计费。OmniCRM使用CGRateS作为OCS平台。
OCS配置
文件: /OmniCRM-API/Provisioners/ocs.py
配置:
# crm_config.yaml
ocs:
cgrates: "10.64.12.160:2080"
ocsTenant: "mnc380.mcc313.3gppnetwork.org"
ocsApi: "http://10.64.12.160:2080"
SIM服务的OCS组件
1. 过滤器 - 用户识别
过滤器通过网络请求识别用户:
{
"ID": "FILTER_IMSI_Service_abc123",
"Type": "*string",
"Element": "~*req.OriginHost",
"Values": ["310120123456789"]
}
2. 属性 - 账户映射
属性将IMSI映射到计费账户:
{
"ID": "ATTR_ACCOUNT_Service_abc123",
"FilterIDs": ["FILTER_IMSI_Service_abc123"],
"Attributes": [
{
"Path": "*req.Account",
"Value": "Service_abc123"
},
{
"Path": "*req.Bandwidth",
"Value": "100000000" // 100 Mbps
}
]
}
3. 资源 - 会话限制
资源控制并发会话限制:
{
"ID": "RES_SESSIONS_Service_abc123",
"FilterIDs": ["FILTER_IMSI_Service_abc123"],
"Limit": 5, // 最大5个并发会话
"UsageTTL": "-1"
}
4. 统计 - 使用跟踪
统计队列跟踪使用情况以进行分析:
{
"ID": "STATS_Service_abc123",
"FilterIDs": ["FILTER_IMSI_Service_abc123"],
"Metrics": [
"*sum#~*req.Usage",
"*tcc" // 总通话次数
]
}
5. 行动计划 - 定期收费
行动计划处理每月收费等重复操作:
{
"Id": "ActionPlan_Service_abc123_Monthly",
"ActionsId": "Action_Add_Monthly_Data",
"Timing": {
"MonthDays": [1], // 每月1日
"Time": "00:00:00Z"
}
}
OCS API功能
ocs.py中的关键功能:
async def async_get_balance(account, server, tenant):
"""获取当前账户余额"""
async def async_topup_dongle(tenant, account, server, days):
"""添加基于时间的数据配额"""
def Get_Account_Status(account, server, tenant):
"""获取全面的账户信息"""
def CGRateS_API_Call(method, params, server, tenant):
"""通用CGRateS JSON-RPC API调用"""
SIM库存对账
OmniCRM包括工具以确保CRM库存与HSS之间的一致性。
对账脚本
文件: /OmniCRM-API/Provisioners/hss_reconcile.py
目的:
- 识别HSS中但不在库存中的SIM(孤立的)
- 查找未在HSS中配置的分配SIM
- 验证MSISDN格式
- 生成HTML报告
执行的检查:
-
HSS中的已售SIM:
- 从库存查询所有分配的SIM
- 检查每个IMSI是否存在于HSS中
- 报告分配给客户但不在HSS中的SIM
-
库存中的已配置SIM:
- 从HSS查询所有用户
- 检查每个IMSI是否存在于库存中
- 报告孤立的HSS条目
-
MSISDN验证:
- 验证电话号码格式
- 检查是否符合澳大利亚号码标准
- 报告格式错误的号码
运行对账:
python hss_reconcile.py
输出:
- 带有颜色编码结果的HTML报告
- 不匹配项的列表以供调查
- 清理建议
最佳实践:
- 每周运行对账
- 及时调查差异
- 使用报告识别配置失败
- 清理孤立条目以释放资源
SIM配置故障排除
常见问题及解决方案
问题:SIM配置失败,显示“IMSI已存在于HSS”
- 原因: IMSI已在先前尝试中配置
- 解决方案: 检查HSS中是否存在现有用户,采取以下措施:
- 如果孤立,删除现有用户
- 更新现有用户,而不是创建新用户
- 运行对账以识别冲突
问题:eSIM二维码未生成
- 原因:
management_url字段未填充LPA代码 - 解决方案: 确保eSIM导入脚本正确设置
management_url - 格式: 必须为
LPA:1$server$activation-code
问题:库存项目显示为“可用”,但已分配
- 原因: 配置在库存分配之前失败
- 解决方案: 检查配置事件以获取失败原因
- 修复: 完成配置或将库存返回池中
问题:客户无法拨打电话(数据正常)
- 原因: IMS用户未配置
- 解决方案: 检查IMS配置步骤是否完成
- 修复: 手动配置IMS用户或重新运行剧本
问题:认证失败(SIM无法连接)
- 原因: SIM卡和HSS之间的Ki/OPC不匹配
- 解决方案: 验证AuC凭据是否与物理SIM匹配
- 修复: 使用正确的凭据更新HSS AuC
问题:自助注册未能分配SIM
- 原因: 库存中没有可用的SIM
- 解决方案: 检查库存中状态为“新”的SIM和customer_id为NULL的SIM
- 修复: 导入新的SIM批次或将返回的SIM标记为“已使用”
调试提示
1. 检查配置事件:
GET /crm/provision/provision_id/{id}
查找失败的任务(状态2)并查看错误消息。
2. 验证HSS用户:
GET {hss_url}/subscriber/msisdn/{phone_number}
检查用户是否存在并具有正确的配置。
3. 检查OCS账户:
{
"method": "ApierV2.GetAccount",
"params": [
{
"Tenant": "mnc380.mcc313.3gppnetwork.org",
"Account": "Service_abc123"
}
]
}
4. 查询库存状态:
GET /crm/inventory/?filters={"itemtext2":["310120123456789"]}
通过IMSI搜索以查找库存项目并检查其状态。
5. 查看Ansible日志:
检查/var/log/ansible/或配置事件详细信息以获取完整的剧本输出。
最佳实践
SIM库存管理
- 批量导入: 使用导入脚本处理大型SIM批次
- 定期对账: 每周运行HSS/库存对账
- 状态管理: 保持库存状态准确(新、已分配、已使用)
- 供应商跟踪: 记录SIM供应商和批次信息
- 成本跟踪: 维护准确的批发/零售成本
安全性
- 凭据分离: 身份验证凭据(Ki/OPC)仅保留在HSS中,永远不在CRM中
- 访问控制: 限制谁可以分配/修改SIM库存
- 审计日志: 跟踪所有SIM分配和更改
- PIN/PUK管理: PIN/PUK代码存储在HSS中,通过安全渠道提供给客户
- 丢失/被盗流程: 立即在HSS中暂停服务并标记库存状���
配置
- 验证: 始终验证IMSI格式和唯一性
- 回滚: 使用块/恢复模式在失败时进行自动清理
- 通知: 向客户发送明确的激活说明
- 测试: 在生产之前测试配置
- 监控: 跟踪配置成功率和失败原因
eSIM特定
- LPA格式: 在存储之前验证LPA代码格式
- 二维码测试: 在多台设备上测试二维码
- 激活说明: 提供清晰的逐步指南
- 配置文件管理: 跟踪eSIM配置文件的下载和安装
- 备份代码: 在二维码扫描失败的情况下提供手动LPA代码