Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Using puppet to realize automatic operation and maintenance

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)06/03 Report--

Using puppet to realize automatic operation and maintenance

Service Overview:

1. What is puppet

Puppet is a configuration management software designed for automatic management of data centers. Is a Linux, Unix platform centralized configuration management system, using Ruby language, can manage configuration files, users, cron tasks, software packages, system services and so on. Puppet calls these system entities resources. The design goal of puppet is to simplify the management of these resources and properly deal with the dependencies between resources.

2. The working mode of Puppet

Puppet is a configuration management tool for the Cramp S architecture that installs the puppet-server package (called Puppetmaster) on a central server. Install the puppet client software (known as PuppetClient) on the target host that needs to be managed. When the client connects to the Puppetmaster, the configuration file defined on the Puppetmaster is compiled and run on the client. By default, each client communicates with the server every half hour to confirm the update of the configuration information. If there is new configuration information or if the configuration information has changed, the configuration will be recompiled and released to each client for execution. You can also actively trigger an update of configuration information on the server to force each client to configure. If the configuration information of the client is changed, it can obtain the original configuration from the server to correct it. The server side of puppet holds all the configuration code for the client server, which is called manifest in puppet. The manifest (list) is stored on the puppetmaster server. After the puppet client downloads manifest, the server can be configured according to manifest, such as package management, user management, file management, and so on.

Port: 8140

3. Operation principle

1) the client puppetd calls facter,facter to detect some variables of the host, such as hostname, memory size, IP address, and so on. Puppetd then sends this information to the server.

2) the puppetmaster on the server side detects the hostname of the client, and then goes to the corresponding node configuration in manifest, and then parses the content. The information sent by facter can be processed as variables, the code involved in node is parsed, and the other code is not parsed. Parsing is divided into several processes: syntax checking, and then generating an intermediate pseudo code, and then sending the pseudo code to the client.

3) after receiving the pseudo code, the client will execute it, and the client will send the execution result to the server.

4-the server then writes the execution result of the client to the log.

4. Note:

1) to ensure security: install openssl, openssl-devel, client and server communication based on ssl and certificate communication. Only puppetmaster server-certified puppet client can communicate with puppetmaster server. CA certificate.

2) by default, client synchronizes the configuration file with the server once in 30 minutes.

3) based on ruby script. Install the ruby development environment.

Corresponding software:

Software name

Action

Facter-1.6.7.tar.gz

Probe some information on the server

Puppet-2.7.13.tar.gz

Puppet this software package, including puppetmaster server software and puppetd client.

One: experimental objectives

Practice: configure the Puppet server

Actual combat: 5 actual combat cases of Puppet automated operation and maintenance

Second, the experimental environment

Facter-1.6.7.tar.gz

Puppet-2.7.13.tar.gz

Server: xuegod63 IP:192.168.1.63

Client: xuegod64 IP:192.168.1.64

Three: experimental code

Preparations for setting up the puppet server and puppet client:

Puppet requires all machines to have a full domain name (FQDN).

Match: the hostname keeps the time synchronization between the two servers. Only when the time is synchronized can the CA authentication be passed, and iptables and selinux should be closed at the same time.

The following works on both xueogd63 and xuegod64: Puppet requires all machines to have a full domain name (FQDN).

1. Configure the xuegod63 and xuegod64 environment

1) hostname synchronization

[root@xuegod63 ~] # cat / etc/hosts

192.168.1.63 xuegod63.cn

192.168.1.64 xuegod64.cn

[root@xuegod63 ~] # scp / etc/hosts 192.168.1.64:/etc/ # hosts configuration file copied to xuegod64

2) keep the two servers synchronized

[root@xuegod63 ~] # cat / etc/ntp.conf

Server 0.rhel.pool.ntp.org

Server 1.rhel.pool.ntp.org

Server 2.rhel.pool.ntp.org

[root@xuegod63 ~] # ntpdate 0.rhel.pool.ntp.org #

15 Dec 20:36:57 ntpdate [3652]: step time server 202.112.31.197 offset 31.527473 sec

[root@xuegod63 ~] # date

Mon Dec 15 20:37:14 CST 2014

[root@xuegod63 64] # crontab-e

* / 5 * / usr/sbin/ntpdate 0.rhel.pool.ntp.org &

3) keep the domain name consistent

[root@xuegod63 ~] # cat / etc/sysconfig/network

NETWORKING=yes

HOSTNAME=xuegod63.cn

[root@xuegod64 ~] # cat / etc/sysconfig/network

NETWORKING=yes

HOSTNAME=xuegod64.cn

2. Xuegod63 installs puppet server

Upload the software package:

Facter-1.6.7.tar.gz # probe some information on the server

Puppet-2.7.13.tar.gz # puppet includes puppetmaster server software and puppetd client software package

1) install ruby openssl openssl-devel:

[root@xuegod63 ~] # yum install openssl openssl-devel

[root@xuegod63 ~] # yum install ruby-y

Note: facter-1.6.7.tar.gz and puppet-2.7.13.tar.gz are installed on both xuegod63 and xuegod64. The difference between which host is the server and the client is that the server script is generated differently on each machine.

2) install: facter-1.6.7.tar.gz

[root@xuegod63 ~] # tar zxvf facter-1.6.7.tar.gz

[root@xuegod63 ~] # cd facter-1.6.7

[root@xuegod63 facter-1.6.7] # ruby install.rb

3) install: puppet-2.7.13.tar.gz

[root@xuegod63 ~] # tar zxvf puppet-2.7.13.tar.gz

[root@xuegod63 ~] # cd puppet-2.7.13

[root@xuegod63 puppet-2.7.13] # ruby install.rb

4) xuegod63 replication configuration file:

[root@xuegod63 puppet-2.7.13] # cp conf/redhat/fileserver.conf / etc/puppet/

[root@xuegod63 puppet-2.7.13] # cp conf/redhat/puppet.conf / etc/puppet/

[root@xuegod63 puppet-2.7.13] # mkdir / etc/puppet/manifests

[root@xuegod63 puppet-2.7.13] # cd / etc/puppet/

[root@xuegod63 puppet] # ls

Auth.conf fileserver.conf manifests puppet.conf

Parameter description:

/ / auth.conf-- > ACL profile accessed by puppet server to client

/ / fileserver.conf-- > puppet server as the ACL configuration file for the file server

/ / manifests-- > Puppet script main file directory, at least need to contain site.pp file, site.pppuppet master file (entry file). All actions to be performed on the server are written in the file at the end of this .pp.

/ / puppet.conf-- > Puppet server configuration file

5) set the boot script:

[root@xuegod63 puppet-2.7.13] # cp conf/redhat/server.init / etc/init.d/puppetmaster

[root@xuegod63 puppet-2.7.13] # chmod + x! $

Chmod + x / etc/init.d/puppetmaster

[root@xuegod63 puppet-2.7.13] # chkconfig puppetmaster on

[root@xuegod63 puppet-2.7.13] # chkconfig-- list puppetmaster

Puppetmaster 0:off 1:off 2:on 3:on 4:on 5:on 6:off

6) generate puppet users:

[root@xuegod63 puppet-2.7.13] # grep puppet / etc/passwd # previous check, there is no puppet user.

[root@xuegod63 puppet-2.7.13] # chmod + x / etc/init.d/puppetmaster

[root@xuegod63 puppet-2.7.13] # puppetmasterd-- mkusers # generate users

[root@xuegod63 puppet-2.7.13] # grep puppet / etc/passwd # View users

Puppet:x:500:500::/home/puppet:/bin/bash

7) start the service

[root@xuegod63 puppet-2.7.13] # / etc/init.d/puppetmaster start

Starting puppetmaster:

[root@xuegod63 puppet-2.7.13] # netstat-antup | grep 8140

Tcp 0 0 0.0.0.0 8140 0.0.0.015 * LISTEN 4750/ruby

[root@xuegod63 puppet-2.7.13] # lsof-I: 8140

COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME

Puppetmas 4750 puppet 7u IPv4 28000 0t0 TCP *: 8140 (LISTEN)

3. Install the client: xuegod64.cn

1) install ruby openssl openssl-devel:

[root@xuegod63 ~] # scp facter-1.6.7.tar.gz puppet-2.7.13.tar.gz 192.168.1.64:/root

[root@xuegod64 ~] # yum install openssl openssl-devel

[root@xuegod64 ~] # yum install ruby-y

2) install: facter-1.6.7.tar.gz

[root@xuegod64 ~] # tar zxvf facter-1.6.7.tar.gz

[root@xuegod64 ~] # cd facter-1.6.7

[root@xuegod64 facter-1.6.7] # ruby install.rb

3) install: puppet

[root@xuegod64 ~] # tar zxvf puppet-2.7.13.tar.gz

[root@xuegod64 ~] # cd puppet-2.7.13

[root@xuegod64 puppet-2.7.13] # ruby install.rb

4) copy the configuration file:

[root@xuegod64 puppet-2.7.13] # cp conf/namespaceauth.conf / etc/puppet/

[root@xuegod64 puppet-2.7.13] # cp conf/redhat/puppet.conf / etc/puppet/

5) set the boot script:

[root@xuegod64 puppet-2.7.13] # cp conf/redhat/client.init / etc/init.d/puppet

[root@xuegod64 puppet-2.7.13] # chmod + x / etc/init.d/puppet

[root@xuegod64 puppet-2.7.13] # chkconfig puppet on

6) configure xuegod64 puppet profile: specify puppetmaster hostname and client certificate name

[root@xuegod64 puppet-2.7.13] # vim / etc/puppet/puppet.conf # insert the following red content

[main]

# The Puppet log directory.

# The default value is'$vardir/log'.

Logdir = / var/log/puppet

# Where Puppet PID files are kept.

# The default value is'$vardir/run'.

Rundir = / var/run/puppet

# Where SSL certificates are kept.

# The default value is'$confdir/ssl'.

Ssldir = $vardir/ssl

[agent]

# The file in which puppetd stores a list of the classes

# associated with the retrieved configuratiion. Can be loaded in

# the separate ``uplopet``executable using the ``--loadclasses``

# option.

# The default value is'$confdir/classes.txt'.

Classfile = $vardir/classes.txt

Server = xuegod63.cn

Certname = xuegod64.cn

# Where puppetd caches the local configuration. An

# extension indicating the cache format is added automatically.

# The default value is'$confdir/localconfig'.

Localconfig = $vardir/localconfig

Note:

Server = xuegod63.cn # specify the puppetmaster hostname

Certname = xuegod64.cn # client certificate name

7) start the service

[root@xuegod64 puppet-2.7.13] # puppetmasterd-- mkusers # generate users

[root@xuegod64 puppet-2.7.13] # / etc/init.d/puppet start

[root@xuegod64 puppet-2.7.13] # netstat-antup | grep 8140

Tcp 0 0 0.0.0.0 8140 0.0.0.015 * LISTEN 2829/ruby

Note: found that both the server and the client start port 8140

[root@xuegod63 ~] # netstat-antup | grep 8140

Tcp 0 0 0.0.0.0 8140 0.0.0.015 * LISTEN 4750/ruby

4. Signature certificate: client xuegod64 looks for xuegod63 signature

1) Xuegod64 send request: generate certificate request file

[root@xuegod64 puppet-2.7.13] # puppetd-test-server xuegod63.cn

Err: Could not retrieve catalog from remote server: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed. This is often because the time is out of sync on the server or client

Warning: Not using cache on failed catalog

Err: Could not retrieve catalog; skipping run

Err: Could not send report: SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed. This is often because the time is out of sync on the server or client

If something goes wrong, the solution: some files are not signed by the certificate.

[root@xuegod64 puppet-2.7.13] # rm-rf / var/lib/puppet/ssl/*

[root@xuegod64 puppet-2.7.13] # puppetd-test-server xuegod63.cn

[root@xuegod64 puppet-2.7.13] # echo $? # returned as 1, no problem.

one

2) xuegod63 to see which server certificate request files are available

[root@xuegod63 puppet-2.7.13] # puppetca-- list # to see which servers have requested certificate signatures.

Xuegod64.cn (DB:28:A7:03:C1:B5:55:4E:68:9E:07:0E:91:4D:7C:CB)

3) sign the request file

[root@xuegod63 puppet-2.7.13] # puppetca-s xuegod64.cn # signs only a client. Server-a signifies that all request files are signed, and xuegod64 signature

Notice: Signed certificate request for xuegod64.cn

Notice: Removing file Puppet::SSL::CertificateRequest xuegod64.cn at'/ var/lib/puppet/ssl/ca/requests/xuegod64.cn.pem'

[root@xuegod63 puppet-2.7.13] # puppetca-s-a # sign all clients

No waiting certificate requests to sign

[root@xuegod63 puppet-2.7.13] # ls / var/lib/puppet/ssl/ca/requests/ # empty, no files

[root@xuegod63 puppet-2.7.13] # ls / var/lib/puppet/ssl/ca/signed/

Xuegod63.cn.pem xuegod63.pem xuegod64.cn.pem

4) check the certificate signature. It is preceded by a + sign, which indicates that the certificate has been signed successfully.

[root@xuegod63 puppet-2.7.13] # puppetca-a-- list

+ xuegod63.cn (24:49:4F:DC:0B:55:CD:50:F9:A6:D0:F9:BA:56:A1:D6) (alt names: DNS:puppet, DNS:puppet.cn, DNS:xuegod63.cn)

+ xuegod64.cn (D1:2D:D4:95:38:46:F0:B4:A8:7E:58:5D:ED:89:35:84)

The location of the certificate signed by the server

[root@xuegod63 puppet-2.7.13] # ls / var/lib/puppet/ssl/ca/signed/* # server signed certificate location

/ var/lib/puppet/ssl/ca/signed/xuegod63.cn.pem

/ var/lib/puppet/ssl/ca/signed/xuegod64.cn.pem

5) xuegod64 restarts the server, obtains the new CA certificate available, and uses the new CA certificate to communicate with the server:

[root@xuegod64 puppet-2.7.13] # ls / var/lib/puppet/ssl/certs/

Ca.pem

[root@xuegod64 puppet-2.7.13] # / etc/init.d/puppet restart

[root@xuegod64 puppet-2.7.13] # ls / var/lib/puppet/ssl/certs/

Ca.pem xuegod64.cn.pem

# you can see the certificate, indicating that the client and server are communicating normally. =

5. Examples of automatic operation and maintenance:

Practice 1, create a file test.txt in the / tmp directory of xuegod64 remotely through puppet, and write the contents: Welconme

Method 1:

1) xuegod63 server configuration:

[root@xuegod63 puppet-2.7.13] # vim / etc/puppet/manifests/site.pp

[root@xuegod63 puppet-2.7.13] # cat / etc/puppet/manifests/site.pp

Node default {

File {"/ tmp/test.txt":

Content= > "this is a test file"

}

}

[root@xuegod63 puppet-2.7.13] # / etc/init.d/puppetmaster restart

2) Test whether the client can create files automatically

Method 1 executes the script by restarting the puppet client service

[root@xuegod64 puppet-2.7.13] # / etc/init.d/puppet restart

[root@xuegod64 puppet-2.7.13] # cat / tmp/test.txt

This is a test file

Method 2:

1) synchronization takes effect temporarily

[root@xuegod64 puppet-2.7.13] # puppetd-test-server xuegod63.cn

Info: Caching catalog for xuegod64.cn

Info: Applying configuration version '1429357828'

Notice: Finished catalog run in 0.10 seconds

[root@xuegod64 puppet-2.7.13] # cat / tmp/test.txt

This is a test file

Method 3: wait 30 minutes and then synchronize yourself.

Example 2: file distribution.

To publish a.txt (apache-4.1.12.rpm) from the / opt directory on the server server to the / opt directory of the client server, the file name remains the same. Note: when distributing files, do not use / root, there will be permission issues.

1) xuegod63 configuration:

[root@xuegod63 ~] # cp / etc/hosts / opt/a.txt

[root@xuegod63 ~] # vim / etc/puppet/fileserver.conf # append the following at the end of the file

[files]

Path / opt/

Allow 192.168.1.0/24

Note: [files] # name, you can write it as you like

2) specify the actions that the client will perform:

[root@xuegod63 ~] # vim / etc/puppet/manifests/site.pp

[root@xuegod63 ~] # cat / etc/puppet/manifests/site.pp # add red content

Node default {

File {"/ tmp/test.txt":

Content= > "this is a test file"

}

File {"/ opt/a.txt":

Source = > "puppet://$puppetserver/files/a.txt"

# / / xuegod63.cn//opt/a.txt

}

}

Note:

File {"/ opt/a.txt": # refers to the path distributed to the client

Source = > "puppet://$puppetserver/files/a.txt", the files in should be the same as the name defined in / etc/puppet/fileserver.conf.

Note: after modifying the site.pp file, the server does not need to restart the service.

3) synchronization takes effect temporarily

[root@xuegod64 puppet-2.7.13] # puppetd-test-server xuegod63.cn

Info: Caching catalog for xuegod64.cn

Info: Applying configuration version '1418651351'

Notice: / stage [main] / Node [default] / File [/ opt/a.txt] / ensure: defined content as'{md5} e7d6d91a44650a85573b0cd47f2c1647'

Notice: Finished catalog run in 0.46 seconds

[root@xuegod64 puppet-2.7.13] # ls / opt/ # View

A.txt

[root@xuegod64 puppet-2.7.13] # cat / opt/a.txt

127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4

:: 1 localhost localhost.localdomain localhost6 localhost6.localdomain6

192.168.1.63 xuegod63.cn

192.168.1.64 xuegod64.cn

Practice 3: automatically modify file properties

1) xuegod63 scripting configuration

[root@xuegod64 ~] # ll / opt/a.txt

-rw-r--r-- 1 root root 210 October 22 16:31 / opt/a.txt

[root@xuegod63 ~] # cat / etc/puppet/manifests/site.pp

Node default {

File {"/ tmp/test":

Content= > "this is a test file"

}

File {"/ opt/a.txt":

Source = > "puppet://$puppetserver/files/a.txt"

Owner = > "puppet"

Group = > "puppet"

Mode = > 777

}

}

Note: the code of the previous experiment needs to be deleted.

2) synchronous temporary effective test:

[root@xuegod64 puppet-2.7.13] # puppetd-test-server xuegod63.cn

Info: Caching catalog for xuegod64.cn

Info: Applying configuration version '1418651544'

Notice: / stage [main] / Node [default] / File [/ opt/a.txt] / owner: owner changed 'root' to' puppet'

Notice: / stage [main] / Node [default] / File [/ opt/a.txt] / group: group changed 'root' to' puppet'

Notice: / stage [main] / Node [default] / File [/ opt/a.txt] / mode: mode changed '0644' to' 0777'

Notice: Finished catalog run in 0.30 seconds

[root@xuegod64 puppet-2.7.13] # ll / opt/a.txt

-rwxrwxrwx 1 puppet puppet 213 Dec 15 21:49 / opt/a.txt

Example 4: the server side lets the client side automatically execute shell scripts or commands

The shell script is executed through the puppet distribution, then the test.sh script is executed in the client's / opt directory, and after the script is executed, an testfile file is created in the / tmp directory.

1) Edit the test script

[root@xuegod63 ~] # vim / opt/test.sh

#! / bin/bash

/ bin/touch / tmp/testfile

2) Edit script

[root@xuegod63 opt] # vim / etc/puppet/manifests/site.pp # writes the following red markings

Node default {

File {"/ tmp/test":

Content= > "this is a test file"

}

File {"/ opt/a.txt":

Source = > "puppet://$puppetserver/files/a.txt"

Owner = > "puppet"

Group = > "puppet"

Mode = > 777

}

File {"/ opt/test.sh":

Source = > "puppet://$puppetserver/files/test.sh"

Owner = > "puppet"

Group = > "puppet"

Mode = > 755

}

Exec {"exec-mkdir":

Cwd = > "/ opt"

Command = > "sh / opt/test.sh"

User = > "puppet"

Path = > "/ usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"

}

}

Note: there is no need to restart the server.

3) synchronous testing:

[root@xuegod64 puppet-2.7.13] # puppetd-test-server xuegod63.cn

Info: Caching catalog for xuegod64.cn

Info: Applying configuration version '1418651975'

Notice: / stage [main] / Node [default] / ensure [/ opt/test.sh] / ensure: defined content as'{md5} d68e2194d349dcc3f1990a0ce37dcf1a'

Notice: / Stage[main] / / Node[default] / Exec [exec-mkdir] / returns: executed successfully

Notice: Finished catalog run in 1.85 seconds

[root@xuegod64 puppet-2.7.13] # ls / tmp/testfile

/ tmp/testfile

[root@xuegod64 puppet-2.7.13] # ll / opt/

Total 8

-rwxrwxrwx 1 puppet puppet 213 Dec 15 21:49 a.txt

-rwxr-xr-x 1 puppet puppet 37 Dec 15 21:59 test.sh

Example 5: the client automatically starts and shuts down the service:

You can restart some services, status and other operations through puppet. Puppet is operated through the service command. Therefore, you can only target the service instance in the / etc/init.d/ directory: turn off the vsftpd service of the client xuegod64 and start the nfs service.

1) prepare the environment:

[root@xuegod64] # rpm-ivh / mnt/Packages/vsftpd-2.2.2-6.el6_0.1.x86_64.rpm

[root@xuegod64 ~] # service vsftpd start # in order to turn off the service remotely, it is open here first.

[root@xuegod64 ~] # service nfs stop

[root@xuegod64 ~] # service vsftpd status

[root@xuegod64 ~] # service nfs status

2) draw the manifests menu to configure how the client executes:

[root@xuegod63 opt] # cat / etc/puppet/manifests/site.pp # add red tag content

Node default {

File {"/ tmp/test":

Content= > "this is a test file"

}

File {"/ opt/a.txt":

Source = > "puppet://$puppetserver/files/a.txt"

Owner = > "puppet"

Group = > "puppet"

Mode = > 777

}

File {"/ opt/test.sh":

Source = > "puppet://$puppetserver/files/test.sh"

Owner = > "puppet"

Group = > "puppet"

Mode = > 755

}

Exec {"exec-mkdir":

Cwd = > "/ opt"

Command = > "sh / opt/test.sh"

User = > "puppet"

Path = > "/ usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin"

}

Service {vsftpd ":

Ensure = > stopped

"nfs":

Ensure = > running

}

}

3) xuegod64 test:

[root@xuegod64] # puppetd-- test-- server xuegod63.cn

[root@xuegod64 ~] # service vsftpd status

Vsftpd is stopped

[root@xuegod64 ~] # service nfs status

Rpc.svcgssd is stopped

Rpc.mountd (pid 8896) is running...

Nfsd (pid 8893 8892 8891 8890 8889 8888 8887 8886) is running...

Rpc.rquotad (pid 8880) is running...

Practice 6: modify synchronization time

Modify puppet client default connection time to puppetmaster default puppet client connects to puppetmaster every 30 minutes, synchronization profile is now modified to 1 minute. Synchronize once.

1) modify the configuration file

[root@xuegod64 ~] # cat / etc/puppet/puppet.conf # add the following red tag content

[main]

# The Puppet log directory.

# The default value is'$vardir/log'.

Logdir = / var/log/puppet

# Where Puppet PID files are kept.

# The default value is'$vardir/run'.

Rundir = / var/run/puppet

# Where SSL certificates are kept.

# The default value is'$confdir/ssl'.

Ssldir = $vardir/ssl

[agent]

# The file in which puppetd stores a list of the classes

# associated with the retrieved configuratiion. Can be loaded in

# the separate ``uplopet``executable using the ``--loadclasses``

# option.

# The default value is'$confdir/classes.txt'.

Classfile = $vardir/classes.txt

Server = xuegod63.cn

Certname = xuegod64.cn

Runinterval = 60 # synchronization interval is wonderful by default

# Where puppetd caches the local configuration. An

[root@xuegod64 ~] # / etc/init.d/puppet restart

[root@xuegod64 ~] # rm-rf / opt/*

[root@xuegod64 ~] # ls / opt/

2) Test: wait 1 minute before checking.

[root@xuegod64 ~] # ls / opt/ # found that the contents of site.pp were executed

A.txt test.sh

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report