一个结束和开始

来到新加坡SeaGroup 工作基本用了两个月,虽然时间比较短,但是可圈点的东西,还是很多。

一、人

这里的人工作很Nice, 模式很简单。基本对你的需求有求必应。有这样一帮小伙伴在一起工作,是很开心的。 还是要感谢很多人,感谢很多帮助过我的人。Kelvin,简称Angk, 不但技术好,人非常Nice. 他给我印象深刻的有以下:
  1. 技术能力过关(只要有技术问题,我一般都会问他,基本上在Django\Data 方面,没有他解决不了的事)
  2. 文档能力优秀。(在工程师里面,我感觉他是文档能力最好的,文档不但写的条理清楚,而且很易读)。一般工程师都喜欢写代码,不喜欢写文档。像这样全面的人,真是公司的财富。同时,也是我日后的榜样。
  3. 为人。人很简单,很热心。我问他几个问题,有时候只是随口一问。他从来不会忘记,不但当时给我详细的解说,事后,还会写出详细的代码样例,帮助我理解。这样的做事风格和态度,也是我在国内的程序员里很难见到的。
以上这三点,我除了文档写得好一些外,其它都做得不好,又是特别想做好的。特别是第三点,日后也一定要这样的为同事打交道,给他们完整的信息和帮助。

二、技术

这两个月,由于掌握的信息有限,所以对公司的业务上写的东西帮助并不大。可以从后面开发上面,我自己倒是学得了很多,
  1. 写Entry Task,再一次熟悉了Django 框架。对Python后端开发的熟悉程序提高很多。特别是软件应用:Cache Redis应用、MessageQueue应用、InfluxDB\Promethus DB 应用\ DB Model 读写分层处理。
  2. Alert Rule Engine。 这里一个从InfluxDb里拿到报警数据然后做Aggregation的一个小程序。这个项目,我做了有三个多星期,从构思、到实现、基本上是一个人完成。也写了较为详细的文档和计划(Basic filter, Standard filter, 和AI filter)一共是这三步,目前也只实现了Baisc 里面的最基本的 CPU/Memory/Disk/Network 这些基本的监控的聚合。 这个应用是我想了很久的程序。没想到,来到了Shopee两个来月,虽然也实现一点点想法。进入下一家公司也可以继续使用。
  3. CMDB。在临行,就开始考虑拉下来公司的基础架构的事了。我首先想到的是CMDB。这样的一个小系统,虽然实现起来,并不是很样的困难,但是很多公司一开始都重视不够,导致系统大了之后,造成很大的运维的困难。造成的困难很多,也很关键。比如: 自动化部署、自动化监控、报告等。这是运维的基础,应该首先建好。一个好的CMDB, 不管是人维护还是机器维护,首先可保持精准、稳定、易用性。(性能、扩展、等,都不是在一开始要考虑进来的事)
在完成以上任务的同时,我又不得不考虑另外一个重要因素 — 基础算法。在很久时间,我都忽略了这种东西重要性,以至于很晚的今天才接意识到。在考虑Alert Rule Engine 和CMDB的时候,我发现,当要自己设计一个系统时,如何准确、高效的处理数据,是最最关键的部分。花了一个来星期时间,我了解到OOP Pattern Design、了到 Insertion Sort、Binary Search Tree、Linked List 等算法实现。这些都给我了很大的启发。

三、事与态度

 在临走之前,在熟悉了一点点业务的同时,也做出来一点CMDB的Schema,还是有些欣慰的。时间并没有白白费掉。另外,我感觉到了懂得原理的重要性。一个合格的工程师,是会把很多技术工具模型熟念于心的。在使用工具的同时,要做到
  1. 要使懂得工具内部如何实现;
  2. 要懂得如何恰当的使用轮子;
  3. 要懂得如何创造自己的轮子。不可完全依赖它人的算法、逻辑。(很多时候,必要要学会如何创造出合适自己的轮子来。)
先说这样说吧,以上三点,就是这两个多月来,我最大的收获。这些宝贵的东西,将在我接下来的职业生涯乃至人生里面,都会默默的产生力量。我希望可以一以贯之、使自己的认识和能力更可精进一步。
2018.5.18

技术诚可贵,生命价更高

技术值钱。因为,时间宝贵,生命宝贵。
一个小小的技术细节,如果不理解,不懂得,就会让人花了个把个小时去攻破。在个解决问题的过程之中,自己完全忽略外界,整个人被占有。一旦问题解决,自己马上就释放出来。这些宝贵的时间,就在一点一滴中度过了。
不但时间花费过去,整个人的健康也在其中被消耗掉了。干技术的,一旦技术一更新,又得撅着屁股学新的,学习的代价昂贵,耗费精力之大,所以不得不说,技术值钱,是有道理的。
然而,有没有更好的体现值钱的方法?
技术做得再好,代码写得再好,依然不能替代生活,怎么可以忘记,生活才是人生的主线?
技术付钱,生命更值钱。用有限的生命,去换取一朝一夕的技术,大体上,是不值得的。以此谋生,非要懂得平衡付出和收获不可。
话说回来,即使享受着深入练习、深入思考的快感,过去沉迷也是不好的。
所以,也要在方式、方法上多加分析。
  1. 磨刀不误砍柴工,善用工具。光用苦力,在技术上是无意义的。
  2. 少写,多思考,考虑得差不多了之后再写。多收集经验、有没有成熟模型?有没有同样的人遇到同样的问题?文档是怎么写的。这些都要考虑清楚。
  3. 遇到问题,不做过多纠结。超过1小时以上没有解决,一定是自己的方式错误。要先停下来,和练琴一样。
  4. 写东西之前,先列一个框架。写越大的项目,就越是需要架构能力和框架能力。有了架构,才有了方向。列好之后,分段、分时间解决。例如,有几个核心模块?又有多少子模块?每次的模块花久写?Priority 是什么?每个模块花多少时间?
  5. 要时刻关注原理,而不是表象的功能。
  6. 慢下来,不要急
以点,在解决技术问题时要时刻谨记。

Python 非常奇怪的代码现象

  1. #!/usr/bin/python
    
    
    import os
    from subprocess import *
    import sys
    
    import yaml
    def local_run(cmd):
        if cmd:
            p = Popen(cmd, shell=True, stdout=PIPE,stderr=PIPE)
            out,err = p.communicate()
        return(p.returncode, out, err)
    
    
    if __name__ == '__main__':
        rst = local_run("salt 'dev*' state.apply test  --out=yaml")
        data=yaml.load(rst[1])
        if rst[0] == 0:
            print([ data[k][cmd]['result'] for cmd in data[k].keys() for k in data.keys() ])
            print([ [data[k][cmd]['result'] for cmd in data[k].keys() ] for k in data.keys() ])
            # method 1
            #for k in data.keys():
            #    for cmd in data[k].keys():
            #        print data[k][cmd]['result']
            # method 2
        else:
            print rst[2]
            [ data[k][cmd]['result'] for cmd in data[k].keys() for k in data.keys() ]
            sys.exit(rst[0])
    
    

    Traceback (most recent call last):

      File “test.py”, line 20, in <module>

        print([ data[k][cmd][‘result’] for cmd in data[k].keys() for k in data.keys() ])

    NameError: name ‘k’ is not defined

    2. 将两个Expression 对掉,却能生效

    #!/usr/bin/python
    
    
    import os
    from subprocess import *
    import sys
    
    import yaml
    def local_run(cmd):
        if cmd:
            p = Popen(cmd, shell=True, stdout=PIPE,stderr=PIPE)
            out,err = p.communicate()
        return(p.returncode, out, err)
    
    
    if __name__ == '__main__':
        rst = local_run("salt 'dev*' state.apply test  --out=yaml")
        data=yaml.load(rst[1])
        if rst[0] == 0:
            print([ [data[k][cmd]['result'] for cmd in data[k].keys() ] for k in data.keys() ])
            print([ data[k][cmd]['result'] for cmd in data[k].keys() for k in data.keys() ])
            # method 1
            #for k in data.keys():
            #    for cmd in data[k].keys():
            #        print data[k][cmd]['result']
            # method 2
        else:
            print rst[2]
            [ data[k][cmd]['result'] for cmd in data[k].keys() for k in data.keys() ]
            sys.exit(rst[0])

    [[True], [True]]

    [True, True]

    奇怪。

Saltstack Set Roles with Pillar

Saltstack Set Roles with Pillar

Sometimes, we would like to set roles for our servers. This is can be done to define  /srv/pillar/top.sls.

for example

we have:

web_prod01

web_prod02

web_prod02

PART 1 working with pillar

  1. then we can define like this:
base:
   'web_prod*'
       - prod_role

 

2. and in the /srv/pillar/prod_role.sls

role: webserver

3. refresh the pillar file to all matched web_prod*minions

salt “web_prod*” saltutil.refresh_pillar

4. then test it

salt -I ‘role:webserver’ test.ping

additional we can set matched in state file:

base:
 'role:webserver':
   - match: pillar
   - state
   - state2

Reference links:

PART 2 another workaround with external nodegroups

include files in /etc/salt/master

# Include config from several files and directories:

include:

   – /opt/test/saltmgt/nodegroups.yaml

2. cat /opt/test/saltmgt/nodegroups.yaml

nodegroups:

   test1:

     – ‘*prod*’

 

more useful:

Working with Django Model

  1. Sub-queries used for query pk dee in  main talbe

Create your models here.
class projects(models.Model):
    #env = models.ForeignKey(deploy_env, on_delete=models.CASCADE)
    project_name = models.CharField(max_length=200)
    create_date = models.DateTimeField(default=0)
    owner = models.CharField(max_length=200)

    def __str__(self):
        return self.project_name
class AppEnv(models.Model):

    name = models.CharField(max_length=200, unique=True)
    def __str__(self):
        return self.name

class MGDeployEnv(models.Model):
    deploy_env = models.OneToOneField(minion_groups, on_delete=models.CASCADE)
    project_name = models.ForeignKey(projects, on_delete=models.CASCADE)
    env_name = models.ForeignKey(AppEnv, on_delete=models.CASCADE)
    pillar = models.TextField()
    state = models.TextField()
    current_version = models.CharField(max_length=200, blank=True)
    status = models.CharField(max_length=200, blank=True)
    comments = models.CharField(max_length=200, blank=True)
    update_on = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return str(self.deploy_env)
class tasks(models.Model): #question = models.ForeignKey(Question, on_delete=models.CASCADE) #project_name = models.ForeignKey(projects, on_delete=models.CASCADE) env = models.ForeignKey(deploy_env, on_delete=models.CASCADE) deploy_url = models.CharField(max_length=200) owner = models.CharField(max_length=200) date = models.DateTimeField(default=timezone.now) status = models.CharField(max_length=200, blank=True) result = models.TextField(blank=True) def __str__(self): return self.deploy_url

1.1 Command line tests:

>> env_id=deploy_env.objects.filter(project_name_id=5)
>>> qt=tasks.objects.filter(env_id__in=env_id)
>>> qt.values()

<QuerySet [{‘deploy_url’: ‘testurl’, ‘id’: 11, ‘env_id’: 12, ….. etc

class tasks(models.Model):
    #question = models.ForeignKey(Question, on_delete=models.CASCADE)
    #project_name = models.ForeignKey(projects, on_delete=models.CASCADE)
    #env = models.ForeignKey(deploy_env, on_delete=models.CASCADE)
    env = models.ForeignKey(MGDeployEnv, on_delete=models.CASCADE)
    deploy_url = models.CharField(max_length=200)
    owner = models.CharField(max_length=200)
    date = models.DateTimeField(default=timezone.now)
    status = models.CharField(max_length=200, blank=True)
    result = models.TextField(blank=True)

    def __str__(self):
        return self.deploy_url

More Model Query:

There two methods to get the searching result, for example.

1.2 Foward query (query by main set)

if we would like get the all deploy environment of PROD,  or deploy environment of Projects test, we can do following query:

by project

pj=projects.objects.get(project_name=‘abc’)

pj.mgdeployenv_set.all()

or shorter 

projects.objects.get(project_name=‘cpg’).mgdeployenv_set.all()

<QuerySet [<MGDeployEnv: cpg_cons_be>, <MGDeployEnv: cpg_cons_all>]>

by environments

env = AppEnv.objects.get(name=’cons’)

env.mgdeployenv_set.all()

QuerySet [<MGDeployEnv: abc_cons_be>, <MGDeployEnv: abc_cons_all>]>

1.3 BackForward query(query by sub set)

by project

MGDeployEnv.objects.filter(project_name__in=projects.objects.filter(project_name=‘abc’))

<QuerySet [<MGDeployEnv: abc_cons_be>, <MGDeployEnv: abc_cons_all>]>

by environments

MGDeployEnv.objects.filter(env_name__in=AppEnv.objects.filter(name=‘cons’))

<QuerySet [<MGDeployEnv: abc_cons_be>, <MGDeployEnv: abc_cons_all>]>

 

as you can see, this 4 queries are the same.

 

Reference Links:

http://scottlobdell.me/2015/01/sql-database-best-practices-django-orm/ 

 

2. Many to Many

https://docs.djangoproject.com/en/2.0/topics/db/examples/many_to_many/