Cheat Sheet#

server.py, Definition of the per server config
  1# -*- coding: utf-8 -*-
  2
  3"""
  4todo: doc string
  5"""
  6
  7import typing as T
  8import dataclasses
  9
 10from acore_constants.api import ServerLifeCycle
 11
 12
 13@dataclasses.dataclass
 14class Server:
 15    """
 16    Per Game Server configuration.
 17
 18    :param id: Server id, the naming convention is ``${env_name}-${server_name}``.
 19    :param ec2_ami_id: the AMI id for the game server.
 20    :param ec2_instance_type: the EC2 instance type for the game server.
 21    :param ec2_subnet_id: the EC2 subnet id for the game server.
 22    :param ec2_key_name: the EC2 ssh key name for the game server.
 23    :param ec2_eip_allocation_id: if you need a static IP, then create
 24        an Elastic IP address and put the allocation id here. otherwise,
 25        use the automatic public IP address.
 26    :param acore_soap_app_version: the acore_soap_app-project git tag for bootstrap.
 27    :param acore_server_bootstrap_version: the acore_server_bootstrap-project
 28        git tag for bootstrap.
 29    :param db_snapshot_id: the snapshot id to create the RDS DB instance.
 30    :param db_instance_class: the RDS instance class for the game database.
 31    :param db_engine_version: the RDS engine version (all the way to minor).
 32    :param db_admin_username: the RDS admin username, usually this is admin.
 33    :param db_admin_password: the RDS admin password, we need this password.
 34        to create the database user for game server.
 35    :param db_username: the database user for game server.
 36    :param db_password: the database password for game server.
 37    :param lifecycle: the logic "game server (both EC2 and RDS)" lifecycle definition.
 38    :param authserver_conf: custom config for authserver.conf.
 39    :param worldserver_conf: custom config for worldserver.conf.
 40    :param mod_lua_engine_conf: custom config for mod_LuaEngine.conf.
 41    """
 42
 43    id: T.Optional[str] = dataclasses.field(default=None)
 44    # EC2 related
 45    ec2_ami_id: T.Optional[str] = dataclasses.field(default=None)
 46    ec2_instance_type: T.Optional[str] = dataclasses.field(default=None)
 47    ec2_subnet_id: T.Optional[str] = dataclasses.field(default=None)
 48    ec2_key_name: T.Optional[str] = dataclasses.field(default=None)
 49    ec2_eip_allocation_id: T.Optional[str] = dataclasses.field(default=None)
 50    acore_soap_app_version: T.Optional[str] = dataclasses.field(default=None)
 51    acore_db_app_version: T.Optional[str] = dataclasses.field(default=None)
 52    acore_server_bootstrap_version: T.Optional[str] = dataclasses.field(default=None)
 53    # RDS related
 54    db_snapshot_id: T.Optional[str] = dataclasses.field(default=None)
 55    db_instance_class: T.Optional[str] = dataclasses.field(default=None)
 56    db_engine_version: T.Optional[str] = dataclasses.field(default=None)
 57    db_admin_username: T.Optional[str] = dataclasses.field(default=None)
 58    db_admin_password: T.Optional[str] = dataclasses.field(default=None)
 59    db_username: T.Optional[str] = dataclasses.field(default=None)
 60    db_password: T.Optional[str] = dataclasses.field(default=None)
 61    # EC2 and RDS related
 62    lifecycle: T.Optional[str] = dataclasses.field(default=None)
 63    # authserver.conf, worldserver.conf, ...
 64    authserver_conf: T.Dict[str, str] = dataclasses.field(default_factory=dict)
 65    worldserver_conf: T.Dict[str, str] = dataclasses.field(default_factory=dict)
 66    mod_lua_engine_conf: T.Dict[str, str] = dataclasses.field(default_factory=dict)
 67
 68    def __post_init__(self):
 69        if self.lifecycle not in [
 70            ServerLifeCycle.running,
 71            ServerLifeCycle.smart_running,
 72            ServerLifeCycle.stopped,
 73            ServerLifeCycle.deleted,
 74        ]:  # pragma: no cover
 75            raise ValueError(f"{self.lifecycle!r} is not a valid lifecycle definition!")
 76
 77    def is_ready_for_create_new_server(self) -> bool:
 78        """
 79        Check if the configuration is sufficient for creating new server.
 80
 81        See: https://acore-server.readthedocs.io/en/latest/search.html?q=Operation+and+Workflow&check_keywords=yes&area=default#
 82        """
 83        not_none_fields = [
 84            "id",
 85            "ec2_ami_id",
 86            "ec2_instance_type",
 87            "ec2_subnet_id",
 88            "ec2_key_name",
 89            "acore_soap_app_version",
 90            "acore_db_app_version",
 91            "acore_server_bootstrap_version",
 92            "db_instance_class",
 93            "db_engine_version",
 94            "db_admin_username",
 95            "db_admin_password",
 96            "db_username",
 97            "db_password",
 98        ]
 99        for field in not_none_fields:
100            if getattr(self, field) is None:
101                return False
102        return True
103
104    def is_ready_for_create_cloned_server(self) -> bool:
105        """
106        Check if the configuration is sufficient for creating cloned server.
107
108        See: https://acore-server.readthedocs.io/en/latest/search.html?q=Operation+and+Workflow&check_keywords=yes&area=default#
109        """
110        not_none_fields = [
111            "id",
112            "ec2_instance_type",
113            "ec2_subnet_id",
114            "ec2_key_name",
115            "acore_soap_app_version",
116            "acore_db_app_version",
117            "acore_server_bootstrap_version",
118            "db_instance_class",
119            # "db_engine_version", # clone 的时候不需要指定 engine version, 会自动继承
120            # "db_admin_username", # clone 的时候不需要指定 admin username, 会自动继承
121            "db_admin_password",
122            "db_username",
123            "db_password",
124        ]
125        for field in not_none_fields:
126            if getattr(self, field) is None:
127                return False
128        return True
129
130    def is_ready_for_create_updated_server(self) -> bool:
131        """
132        Check if the configuration is sufficient for creating updated server.
133
134        See: https://acore-server.readthedocs.io/en/latest/search.html?q=Operation+and+Workflow&check_keywords=yes&area=default#
135        """
136        not_none_fields = [
137            "id",
138            "ec2_ami_id",
139            "ec2_instance_type",
140            "ec2_subnet_id",
141            "ec2_key_name",
142            "acore_soap_app_version",
143            "acore_db_app_version",
144            "acore_server_bootstrap_version",
145            "db_instance_class",
146            # "db_engine_version", # update server 的时候不需要指定 engine version, 因为我们会用已经存在的数据库
147            # "db_admin_username", # update server 的时候不需要指定 admin username, 因为我们会用已经存在的数据库
148            "db_admin_password",
149            "db_username",
150            "db_password",
151        ]
152        for field in not_none_fields:
153            if getattr(self, field) is None:
154                return False
155        return True
156
157    def is_ready_for_stop_server(self) -> bool:
158        """
159        Check if the configuration is sufficient for stopping server.
160
161        See: https://acore-server.readthedocs.io/en/latest/search.html?q=Operation+and+Workflow&check_keywords=yes&area=default#
162        """
163        not_none_fields = [
164            "id",
165        ]
166        for field in not_none_fields:
167            if getattr(self, field) is None:
168                return False
169        return True
170
171    def is_ready_for_start_server(self) -> bool:
172        """
173        Check if the configuration is sufficient for starting server.
174
175        See: https://acore-server.readthedocs.io/en/latest/search.html?q=Operation+and+Workflow&check_keywords=yes&area=default#
176        """
177        not_none_fields = [
178            "id",
179        ]
180        for field in not_none_fields:
181            if getattr(self, field) is None:
182                return False
183        return True
184
185    def is_ready_for_delete_server(self) -> bool:
186        """
187        Check if the configuration is sufficient for deleting server.
188
189        See: https://acore-server.readthedocs.io/en/latest/search.html?q=Operation+and+Workflow&check_keywords=yes&area=default#
190        """
191        not_none_fields = [
192            "id",
193        ]
194        for field in not_none_fields:
195            if getattr(self, field) is None:
196                return False
197        return True
198
199
200@dataclasses.dataclass
201class ServerMixin:
202    servers: T.Dict[str, Server] = dataclasses.field(default_factory=dict)
203
204    @property
205    def server_blue(self) -> Server:
206        return self.servers["blue"]
207
208    @property
209    def server_green(self) -> Server:
210        return self.servers["green"]
211
212    @property
213    def server_black(self) -> Server:
214        return self.servers["black"]
215
216    @property
217    def server_white(self) -> Server:
218        return self.servers["white"]
219
220    @property
221    def server_yellow(self) -> Server:
222        return self.servers["yello"]
223
224    @property
225    def server_orange(self) -> Server:
226        return self.servers["orange"]
EC2ConfigLoader, config loader for EC2
 1@dataclasses.dataclass
 2class Ec2ConfigLoader:
 3    """
 4    用于在 EC2 上运行脚本, 用 "自省" 的方式获得自己的配置数据. 开始时请使用
 5    :meth:`Ec2ConfigLoader.load` 方法获得当前 EC2 的配置数据.
 6
 7    用法:
 8
 9    .. code-block:: python
10
11        >>> server = Ec2ConfigLoader.load(...)
12        >>> server
13        Server(id='sbx-blue', db_admin_password='sbx*dummy4test', db_username='myuser', db_password='sbx*dummy4test')
14    """
15
16    @classmethod
17    def load(
18        cls,
19        parameter_name_prefix: T.Optional[str] = None,
20        s3folder_config: T.Optional[str] = None,
21        server_id: T.Optional[str] = None,
22        bsm: "BotoSesManager" = default_bsm,
23    ) -> Server:
24        """
25        获得当前 EC2 的配置数据, 返回一个
26        :class:`~acore_server_config.config.define.server.Server` 对象.
27
28        :param parameter_name_prefix: the parameter name prefix, the full name will
29            be ${parameter_name_prefix}-${env_name}.
30        :param s3folder_config: S3 配置数据的根目录, 默认为
31            s3://aws_account_id}-{aws_region}-artifacts/projects/acore_server_config/config/
32        :param server_id: 强制指定 server_id, 跳过 "自省" 阶段. 常用于测试. 这个 server_id
33            的格式为: ${env_name}-${server_name}, 例如: sbx-blue
34        :param bsm: ``boto_session_manager.BotoSesManager`` object, if not provided,
35            then use the current runtime default AWS CLI profile.
36        """
37        if server_id is None:  # pragma: no cover
38            server_id = get_this_server_id(bsm=bsm)
39        env_name, server_name = parse_server_id(server_id=server_id)
40        config = get_config(
41            bsm=bsm,
42            parameter_name_prefix=parameter_name_prefix,
43            env_name=env_name,
44            s3folder_config=s3folder_config,
45        )
46        env = config.get_env(env_name)
47        return env.servers[server_name]
ConfigLoader, config loader for anywhere else
 1@dataclasses.dataclass
 2class Ec2ConfigLoader:
 3    """
 4    用于在 EC2 上运行脚本, 用 "自省" 的方式获得自己的配置数据. 开始时请使用
 5    :meth:`Ec2ConfigLoader.load` 方法获得当前 EC2 的配置数据.
 6
 7    用法:
 8
 9    .. code-block:: python
10
11        >>> server = Ec2ConfigLoader.load(...)
12        >>> server
13        Server(id='sbx-blue', db_admin_password='sbx*dummy4test', db_username='myuser', db_password='sbx*dummy4test')
14    """
15
16    @classmethod
17    def load(
18        cls,
19        parameter_name_prefix: T.Optional[str] = None,
20        s3folder_config: T.Optional[str] = None,
21        server_id: T.Optional[str] = None,
22        bsm: "BotoSesManager" = default_bsm,
23    ) -> Server:
24        """
25        获得当前 EC2 的配置数据, 返回一个
26        :class:`~acore_server_config.config.define.server.Server` 对象.
27
28        :param parameter_name_prefix: the parameter name prefix, the full name will
29            be ${parameter_name_prefix}-${env_name}.
30        :param s3folder_config: S3 配置数据的根目录, 默认为
31            s3://aws_account_id}-{aws_region}-artifacts/projects/acore_server_config/config/
32        :param server_id: 强制指定 server_id, 跳过 "自省" 阶段. 常用于测试. 这个 server_id
33            的格式为: ${env_name}-${server_name}, 例如: sbx-blue
34        :param bsm: ``boto_session_manager.BotoSesManager`` object, if not provided,
35            then use the current runtime default AWS CLI profile.
36        """
37        if server_id is None:  # pragma: no cover
38            server_id = get_this_server_id(bsm=bsm)
39        env_name, server_name = parse_server_id(server_id=server_id)
40        config = get_config(
41            bsm=bsm,
42            parameter_name_prefix=parameter_name_prefix,
43            env_name=env_name,
44            s3folder_config=s3folder_config,
45        )
46        env = config.get_env(env_name)
47        return env.servers[server_name]