ansible笔记(15):变量(二)
参考:http://www.zsythink.net/archives/2671
前一篇文章中已经初步的总结了变量的一些使用方法,这篇文章我们继续,只不过,这篇文章所涉及到的内容需要借助两个模块,所以在详细的总结变量的相关使用方法之前,会先描述一下这两个模块的用法。
当我们运行一个playbook时,默认都会运行一个名为"[Gathering Facts]"的任务,前文中已经大致的介绍过这个默认的任务,ansible通过"[Gathering Facts]"这个默认任务收集远程主机的相关信息(例如远程主机的IP地址,主机名,系统版本,硬件配置等信息),其实,这些被收集到的远程主机信息会保存在对应的变量中,当我们想要使用这些信息时,我们可以获取对应的变量,从而使用这些信息。
如果想要查看"[Gathering Facts]"任务收集的信息内容,我们可以借助一个模块:setup模块
当执行playbook时,playbook其实就是自动调用了setup模块从而执行了"[Gathering Facts]"任务,所以我们可以通过手动执行setup模块查看"[Gathering Facts]"任务收集到的信息,示例如下
上述ad-hoc命令表示收集test70主机的相关信息,执行上述命令后,远程主机test70的相关信息将会输出到ansible主机的控制台上,返回的信息的格式是json格式,我的返回信息如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 | [root@node1 ansible]# ansible test70 -m setup test70 | SUCCESS => { "ansible_facts" : { "ansible_all_ipv4_addresses" : [ "192.168.1.70" ], "ansible_all_ipv6_addresses" : [], "ansible_apparmor" : { "status" : "disabled" }, "ansible_architecture" : "x86_64" , "ansible_bios_date" : "07/28/2017" , "ansible_bios_version" : "6.00" , "ansible_cmdline" : { "BOOT_IMAGE" : "/vmlinuz-3.10.0-1127.18.2.el7.x86_64" , "LANG" : "zh_CN.UTF-8" , "biosdevname" : "0" , "crashkernel" : "auto" , "net.ifnames" : "0" , "quiet" : true , "rd.lvm.lv" : "centos/root" , "rhgb" : true , "ro" : true , "root" : "/dev/mapper/centos-root" }, "ansible_date_time" : { "date" : "2020-10-09" , "day" : "09" , "epoch" : "1602233781" , "hour" : "16" , "iso8601" : "2020-10-09T08:56:21Z" , "iso8601_basic" : "20201009T165621882645" , "iso8601_basic_short" : "20201009T165621" , "iso8601_micro" : "2020-10-09T08:56:21.882734Z" , "minute" : "56" , "month" : "10" , "second" : "21" , "time" : "16:56:21" , "tz" : "CST" , "tz_offset" : "+0800" , "weekday" : "星期五" , "weekday_number" : "5" , "weeknumber" : "40" , "year" : "2020" }, "ansible_default_ipv4" : { "address" : "192.168.1.70" , "alias" : "eth0" , "broadcast" : "192.168.1.255" , "gateway" : "192.168.1.9" , "interface" : "eth0" , "macaddress" : "00:50:56:b7:ad:4d" , "mtu" : 1500, "netmask" : "255.255.255.0" , "network" : "192.168.1.0" , "type" : "ether" }, "ansible_default_ipv6" : {}, "ansible_device_links" : { "ids" : { "dm-0" : [ "dm-name-centos-root" , "dm-uuid-LVM-wFwSHjPKUqZd3lzYkdpfx8iRARSurcphdG8YqXyGORzhjhEKfnWNefYZ7INpLBHu" ], "dm-1" : [ "dm-name-ceph--2968675b--072a--4a1b--a684--35531a84d574-osd--block--b92fe4bd--4d98--4262--8979--163b08d5d4f0" , "dm-uuid-LVM-Awo4sY1yoYKQMwy8oAVCa18eQXojyMLQnXl9X5ZU5Nz61QM9AdvKqce1v5ZsVswY" ], "dm-2" : [ "dm-name-centos-home" , "dm-uuid-LVM-wFwSHjPKUqZd3lzYkdpfx8iRARSurcphw8yDdAeCspNiiOoGCNhj06acS4UEqWP1" ], "dm-3" : [ "dm-name-centos-opt" , "dm-uuid-LVM-wFwSHjPKUqZd3lzYkdpfx8iRARSurcphtU00ZEsEuUYUbvynCVkMe7tZBUBbOebM" ], "sda2" : [ "lvm-pv-uuid-Ny6LYs-OXSu-cPNb-dUQ1-kcPp-39B9-jbmO20" ], "sdb" : [ "lvm-pv-uuid-xW7J0n-4atk-MkXU-aslt-b96M-fFbk-ZLZB8n" ], "sr0" : [ "ata-VMware_Virtual_SATA_CDRW_Drive_00000000000000000001" ] }, "labels" : {}, "masters" : { "sda2" : [ "dm-0" , "dm-2" , "dm-3" ], "sdb" : [ "dm-1" ] }, "uuids" : { "dm-0" : [ "03898aec-07c2-4cd9-a21f-a8da8c857d12" ], "dm-2" : [ "a635cd7c-d327-4343-95bc-20be4f320c98" ], "dm-3" : [ "8b644eea-a8c6-493c-a1de-6872350348fa" ], "sda1" : [ "5df95799-fa0a-4c3b-babc-c921b333a6d5" ] } }, "ansible_devices" : { "dm-0" : { "holders" : [], "host" : "" , "links" : { "ids" : [ "dm-name-centos-root" , "dm-uuid-LVM-wFwSHjPKUqZd3lzYkdpfx8iRARSurcphdG8YqXyGORzhjhEKfnWNefYZ7INpLBHu" ], "labels" : [], "masters" : [], "uuids" : [ "03898aec-07c2-4cd9-a21f-a8da8c857d12" ] }, "model" : null , "partitions" : {}, "removable" : "0" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "" , "sectors" : "125403136" , "sectorsize" : "512" , "size" : "59.80 GB" , "support_discard" : "512" , "vendor" : null , "virtual" : 1 }, "dm-1" : { "holders" : [], "host" : "" , "links" : { "ids" : [ "dm-name-ceph--2968675b--072a--4a1b--a684--35531a84d574-osd--block--b92fe4bd--4d98--4262--8979--163b08d5d4f0" , "dm-uuid-LVM-Awo4sY1yoYKQMwy8oAVCa18eQXojyMLQnXl9X5ZU5Nz61QM9AdvKqce1v5ZsVswY" ], "labels" : [], "masters" : [], "uuids" : [] }, "model" : null , "partitions" : {}, "removable" : "0" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "" , "sectors" : "33546240" , "sectorsize" : "512" , "size" : "16.00 GB" , "support_discard" : "0" , "vendor" : null , "virtual" : 1 }, "dm-2" : { "holders" : [], "host" : "" , "links" : { "ids" : [ "dm-name-centos-home" , "dm-uuid-LVM-wFwSHjPKUqZd3lzYkdpfx8iRARSurcphw8yDdAeCspNiiOoGCNhj06acS4UEqWP1" ], "labels" : [], "masters" : [], "uuids" : [ "a635cd7c-d327-4343-95bc-20be4f320c98" ] }, "model" : null , "partitions" : {}, "removable" : "0" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "" , "sectors" : "41943040" , "sectorsize" : "512" , "size" : "20.00 GB" , "support_discard" : "512" , "vendor" : null , "virtual" : 1 }, "dm-3" : { "holders" : [], "host" : "" , "links" : { "ids" : [ "dm-name-centos-opt" , "dm-uuid-LVM-wFwSHjPKUqZd3lzYkdpfx8iRARSurcphtU00ZEsEuUYUbvynCVkMe7tZBUBbOebM" ], "labels" : [], "masters" : [], "uuids" : [ "8b644eea-a8c6-493c-a1de-6872350348fa" ] }, "model" : null , "partitions" : {}, "removable" : "0" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "" , "sectors" : "41943040" , "sectorsize" : "512" , "size" : "20.00 GB" , "support_discard" : "512" , "vendor" : null , "virtual" : 1 }, "fd0" : { "holders" : [], "host" : "" , "links" : { "ids" : [], "labels" : [], "masters" : [], "uuids" : [] }, "model" : null , "partitions" : {}, "removable" : "1" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "deadline" , "sectors" : "8" , "sectorsize" : "512" , "size" : "4.00 KB" , "support_discard" : "0" , "vendor" : null , "virtual" : 1 }, "sda" : { "holders" : [], "host" : "Serial Attached SCSI controller: VMware PVSCSI SCSI Controller (rev 02)" , "links" : { "ids" : [], "labels" : [], "masters" : [], "uuids" : [] }, "model" : "Virtual disk" , "partitions" : { "sda1" : { "holders" : [], "links" : { "ids" : [], "labels" : [], "masters" : [], "uuids" : [ "5df95799-fa0a-4c3b-babc-c921b333a6d5" ] }, "sectors" : "409600" , "sectorsize" : 512, "size" : "200.00 MB" , "start" : "2048" , "uuid" : "5df95799-fa0a-4c3b-babc-c921b333a6d5" }, "sda2" : { "holders" : [ "centos-root" , "centos-home" , "centos-opt" ], "links" : { "ids" : [ "lvm-pv-uuid-Ny6LYs-OXSu-cPNb-dUQ1-kcPp-39B9-jbmO20" ], "labels" : [], "masters" : [ "dm-0" , "dm-2" , "dm-3" ], "uuids" : [] }, "sectors" : "209303552" , "sectorsize" : 512, "size" : "99.80 GB" , "start" : "411648" , "uuid" : null } }, "removable" : "0" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "deadline" , "sectors" : "209715200" , "sectorsize" : "512" , "size" : "100.00 GB" , "support_discard" : "512" , "vendor" : "VMware" , "virtual" : 1 }, "sdb" : { "holders" : [ "ceph--2968675b--072a--4a1b--a684--35531a84d574-osd--block--b92fe4bd--4d98--4262--8979--163b08d5d4f0" ], "host" : "Serial Attached SCSI controller: VMware PVSCSI SCSI Controller (rev 02)" , "links" : { "ids" : [ "lvm-pv-uuid-xW7J0n-4atk-MkXU-aslt-b96M-fFbk-ZLZB8n" ], "labels" : [], "masters" : [ "dm-1" ], "uuids" : [] }, "model" : "Virtual disk" , "partitions" : {}, "removable" : "0" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "deadline" , "sectors" : "33554432" , "sectorsize" : "512" , "size" : "16.00 GB" , "support_discard" : "0" , "vendor" : "VMware" , "virtual" : 1 }, "sr0" : { "holders" : [], "host" : "SATA controller: VMware SATA AHCI controller" , "links" : { "ids" : [ "ata-VMware_Virtual_SATA_CDRW_Drive_00000000000000000001" ], "labels" : [], "masters" : [], "uuids" : [] }, "model" : "VMware SATA CD00" , "partitions" : {}, "removable" : "1" , "rotational" : "1" , "sas_address" : null , "sas_device_handle" : null , "scheduler_mode" : "deadline" , "sectors" : "2097151" , "sectorsize" : "512" , "size" : "1024.00 MB" , "support_discard" : "0" , "vendor" : "NECVMWar" , "virtual" : 1 } }, "ansible_distribution" : "CentOS" , "ansible_distribution_file_parsed" : true , "ansible_distribution_file_path" : "/etc/redhat-release" , "ansible_distribution_file_variety" : "RedHat" , "ansible_distribution_major_version" : "7" , "ansible_distribution_release" : "Core" , "ansible_distribution_version" : "7.8" , "ansible_dns" : { "nameservers" : [ "114.114.114.114" , "8.8.8.8" ] }, "ansible_domain" : "" , "ansible_effective_group_id" : 0, "ansible_effective_user_id" : 0, "ansible_env" : { "HOME" : "/root" , "LANG" : "C" , "LC_ALL" : "C" , "LC_NUMERIC" : "C" , "LESSOPEN" : "||/usr/bin/lesspipe.sh %s" , "LOGNAME" : "root" , "LS_COLORS" : "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:" , "MAIL" : "/var/mail/root" , "PATH" : "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin" , "PWD" : "/root" , "SHELL" : "/bin/bash" , "SHLVL" : "2" , "SSH_CLIENT" : "192.168.1.71 45218 22" , "SSH_CONNECTION" : "192.168.1.71 45218 192.168.1.70 22" , "SSH_TTY" : "/dev/pts/1" , "TERM" : "xterm" , "USER" : "root" , "XDG_RUNTIME_DIR" : "/run/user/0" , "XDG_SESSION_ID" : "3773" , "_" : "/usr/bin/python" }, "ansible_eth0" : { "active" : true , "device" : "eth0" , "features" : { "busy_poll" : "off [fixed]" , "fcoe_mtu" : "off [fixed]" , "generic_receive_offload" : "on" , "generic_segmentation_offload" : "on" , "highdma" : "on" , "hw_tc_offload" : "off [fixed]" , "l2_fwd_offload" : "off [fixed]" , "large_receive_offload" : "off" , "loopback" : "off [fixed]" , "netns_local" : "off [fixed]" , "ntuple_filters" : "off [fixed]" , "receive_hashing" : "on" , "rx_all" : "off [fixed]" , "rx_checksumming" : "on" , "rx_fcs" : "off [fixed]" , "rx_gro_hw" : "off [fixed]" , "rx_udp_tunnel_port_offload" : "off [fixed]" , "rx_vlan_filter" : "on [fixed]" , "rx_vlan_offload" : "on" , "rx_vlan_stag_filter" : "off [fixed]" , "rx_vlan_stag_hw_parse" : "off [fixed]" , "scatter_gather" : "on" , "tcp_segmentation_offload" : "on" , "tx_checksum_fcoe_crc" : "off [fixed]" , "tx_checksum_ip_generic" : "on" , "tx_checksum_ipv4" : "off [fixed]" , "tx_checksum_ipv6" : "off [fixed]" , "tx_checksum_sctp" : "off [fixed]" , "tx_checksumming" : "on" , "tx_fcoe_segmentation" : "off [fixed]" , "tx_gre_csum_segmentation" : "off [fixed]" , "tx_gre_segmentation" : "off [fixed]" , "tx_gso_partial" : "off [fixed]" , "tx_gso_robust" : "off [fixed]" , "tx_ipip_segmentation" : "off [fixed]" , "tx_lockless" : "off [fixed]" , "tx_nocache_copy" : "off" , "tx_scatter_gather" : "on" , "tx_scatter_gather_fraglist" : "off [fixed]" , "tx_sctp_segmentation" : "off [fixed]" , "tx_sit_segmentation" : "off [fixed]" , "tx_tcp6_segmentation" : "on" , "tx_tcp_ecn_segmentation" : "off [fixed]" , "tx_tcp_mangleid_segmentation" : "off" , "tx_tcp_segmentation" : "on" , "tx_udp_tnl_csum_segmentation" : "off [fixed]" , "tx_udp_tnl_segmentation" : "off [fixed]" , "tx_vlan_offload" : "on" , "tx_vlan_stag_hw_insert" : "off [fixed]" , "udp_fragmentation_offload" : "off [fixed]" , "vlan_challenged" : "off [fixed]" }, "hw_timestamp_filters" : [], "ipv4" : { "address" : "192.168.1.70" , "broadcast" : "192.168.1.255" , "netmask" : "255.255.255.0" , "network" : "192.168.1.0" }, "macaddress" : "00:50:56:b7:ad:4d" , "module" : "vmxnet3" , "mtu" : 1500, "pciid" : "0000:0b:00.0" , "promisc" : false , "speed" : 10000, "timestamping" : [ "rx_software" , "software" ], "type" : "ether" }, "ansible_eth1" : { "active" : true , "device" : "eth1" , "features" : { "busy_poll" : "off [fixed]" , "fcoe_mtu" : "off [fixed]" , "generic_receive_offload" : "on" , "generic_segmentation_offload" : "on" , "highdma" : "on" , "hw_tc_offload" : "off [fixed]" , "l2_fwd_offload" : "off [fixed]" , "large_receive_offload" : "off" , "loopback" : "off [fixed]" , "netns_local" : "off [fixed]" , "ntuple_filters" : "off [fixed]" , "receive_hashing" : "on" , "rx_all" : "off [fixed]" , "rx_checksumming" : "on" , "rx_fcs" : "off [fixed]" , "rx_gro_hw" : "off [fixed]" , "rx_udp_tunnel_port_offload" : "off [fixed]" , "rx_vlan_filter" : "on [fixed]" , "rx_vlan_offload" : "on" , "rx_vlan_stag_filter" : "off [fixed]" , "rx_vlan_stag_hw_parse" : "off [fixed]" , "scatter_gather" : "on" , "tcp_segmentation_offload" : "on" , "tx_checksum_fcoe_crc" : "off [fixed]" , "tx_checksum_ip_generic" : "on" , "tx_checksum_ipv4" : "off [fixed]" , "tx_checksum_ipv6" : "off [fixed]" , "tx_checksum_sctp" : "off [fixed]" , "tx_checksumming" : "on" , "tx_fcoe_segmentation" : "off [fixed]" , "tx_gre_csum_segmentation" : "off [fixed]" , "tx_gre_segmentation" : "off [fixed]" , "tx_gso_partial" : "off [fixed]" , "tx_gso_robust" : "off [fixed]" , "tx_ipip_segmentation" : "off [fixed]" , "tx_lockless" : "off [fixed]" , "tx_nocache_copy" : "off" , "tx_scatter_gather" : "on" , "tx_scatter_gather_fraglist" : "off [fixed]" , "tx_sctp_segmentation" : "off [fixed]" , "tx_sit_segmentation" : "off [fixed]" , "tx_tcp6_segmentation" : "on" , "tx_tcp_ecn_segmentation" : "off [fixed]" , "tx_tcp_mangleid_segmentation" : "off" , "tx_tcp_segmentation" : "on" , "tx_udp_tnl_csum_segmentation" : "off [fixed]" , "tx_udp_tnl_segmentation" : "off [fixed]" , "tx_vlan_offload" : "on" , "tx_vlan_stag_hw_insert" : "off [fixed]" , "udp_fragmentation_offload" : "off [fixed]" , "vlan_challenged" : "off [fixed]" }, "hw_timestamp_filters" : [], "macaddress" : "00:50:56:b7:86:9b" , "module" : "vmxnet3" , "mtu" : 1500, "pciid" : "0000:13:00.0" , "promisc" : false , "speed" : 10000, "timestamping" : [ "rx_software" , "software" ], "type" : "ether" }, "ansible_fibre_channel_wwn" : [], "ansible_fips" : false , "ansible_form_factor" : "Other" , "ansible_fqdn" : "70" , "ansible_hostname" : "70" , "ansible_hostnqn" : "" , "ansible_interfaces" : [ "lo" , "eth1" , "eth0" ], "ansible_is_chroot" : false , "ansible_iscsi_iqn" : "" , "ansible_kernel" : "3.10.0-1127.18.2.el7.x86_64" , "ansible_kernel_version" : "#1 SMP Sun Jul 26 15:27:06 UTC 2020" , "ansible_lo" : { "active" : true , "device" : "lo" , "features" : { "busy_poll" : "off [fixed]" , "fcoe_mtu" : "off [fixed]" , "generic_receive_offload" : "on" , "generic_segmentation_offload" : "on" , "highdma" : "on [fixed]" , "hw_tc_offload" : "off [fixed]" , "l2_fwd_offload" : "off [fixed]" , "large_receive_offload" : "off [fixed]" , "loopback" : "on [fixed]" , "netns_local" : "on [fixed]" , "ntuple_filters" : "off [fixed]" , "receive_hashing" : "off [fixed]" , "rx_all" : "off [fixed]" , "rx_checksumming" : "on [fixed]" , "rx_fcs" : "off [fixed]" , "rx_gro_hw" : "off [fixed]" , "rx_udp_tunnel_port_offload" : "off [fixed]" , "rx_vlan_filter" : "off [fixed]" , "rx_vlan_offload" : "off [fixed]" , "rx_vlan_stag_filter" : "off [fixed]" , "rx_vlan_stag_hw_parse" : "off [fixed]" , "scatter_gather" : "on" , "tcp_segmentation_offload" : "on" , "tx_checksum_fcoe_crc" : "off [fixed]" , "tx_checksum_ip_generic" : "on [fixed]" , "tx_checksum_ipv4" : "off [fixed]" , "tx_checksum_ipv6" : "off [fixed]" , "tx_checksum_sctp" : "on [fixed]" , "tx_checksumming" : "on" , "tx_fcoe_segmentation" : "off [fixed]" , "tx_gre_csum_segmentation" : "off [fixed]" , "tx_gre_segmentation" : "off [fixed]" , "tx_gso_partial" : "off [fixed]" , "tx_gso_robust" : "off [fixed]" , "tx_ipip_segmentation" : "off [fixed]" , "tx_lockless" : "on [fixed]" , "tx_nocache_copy" : "off [fixed]" , "tx_scatter_gather" : "on [fixed]" , "tx_scatter_gather_fraglist" : "on [fixed]" , "tx_sctp_segmentation" : "on" , "tx_sit_segmentation" : "off [fixed]" , "tx_tcp6_segmentation" : "on" , "tx_tcp_ecn_segmentation" : "on" , "tx_tcp_mangleid_segmentation" : "on" , "tx_tcp_segmentation" : "on" , "tx_udp_tnl_csum_segmentation" : "off [fixed]" , "tx_udp_tnl_segmentation" : "off [fixed]" , "tx_vlan_offload" : "off [fixed]" , "tx_vlan_stag_hw_insert" : "off [fixed]" , "udp_fragmentation_offload" : "on" , "vlan_challenged" : "on [fixed]" }, "hw_timestamp_filters" : [], "ipv4" : { "address" : "127.0.0.1" , "broadcast" : "host" , "netmask" : "255.0.0.0" , "network" : "127.0.0.0" }, "mtu" : 65536, "promisc" : false , "timestamping" : [ "rx_software" , "software" ], "type" : "loopback" }, "ansible_local" : {}, "ansible_lsb" : {}, "ansible_lvm" : { "lvs" : { "home" : { "size_g" : "20.00" , "vg" : "centos" }, "opt" : { "size_g" : "20.00" , "vg" : "centos" }, "osd-block-b92fe4bd-4d98-4262-8979-163b08d5d4f0" : { "size_g" : "16.00" , "vg" : "ceph-2968675b-072a-4a1b-a684-35531a84d574" }, "root" : { "size_g" : "59.80" , "vg" : "centos" } }, "pvs" : { "/dev/sda2" : { "free_g" : "0.00" , "size_g" : "99.80" , "vg" : "centos" }, "/dev/sdb" : { "free_g" : "0" , "size_g" : "16.00" , "vg" : "ceph-2968675b-072a-4a1b-a684-35531a84d574" } }, "vgs" : { "centos" : { "free_g" : "0.00" , "num_lvs" : "3" , "num_pvs" : "1" , "size_g" : "99.80" }, "ceph-2968675b-072a-4a1b-a684-35531a84d574" : { "free_g" : "0" , "num_lvs" : "1" , "num_pvs" : "1" , "size_g" : "16.00" } } }, "ansible_machine" : "x86_64" , "ansible_machine_id" : "2987881be73840df90a217892b5d3a31" , "ansible_memfree_mb" : 3914, "ansible_memory_mb" : { "nocache" : { "free" : 5413, "used" : 392 }, "real" : { "free" : 3914, "total" : 5805, "used" : 1891 }, "swap" : { "cached" : 0, "free" : 0, "total" : 0, "used" : 0 } }, "ansible_memtotal_mb" : 5805, "ansible_mounts" : [ { "block_available" : 5232021, "block_size" : 4096, "block_total" : 5240320, "block_used" : 8299, "device" : "/dev/mapper/centos-home" , "fstype" : "xfs" , "inode_available" : 10485709, "inode_total" : 10485760, "inode_used" : 51, "mount" : "/home" , "options" : "rw,relatime,attr2,inode64,noquota" , "size_available" : 21430358016, "size_total" : 21464350720, "uuid" : "a635cd7c-d327-4343-95bc-20be4f320c98" }, { "block_available" : 783, "block_size" : 4096, "block_total" : 50345, "block_used" : 49562, "device" : "/dev/sda1" , "fstype" : "xfs" , "inode_available" : 6435, "inode_total" : 6776, "inode_used" : 341, "mount" : "/boot" , "options" : "rw,relatime,attr2,inode64,noquota" , "size_available" : 3207168, "size_total" : 206213120, "uuid" : "5df95799-fa0a-4c3b-babc-c921b333a6d5" }, { "block_available" : 14711559, "block_size" : 4096, "block_total" : 15667738, "block_used" : 956179, "device" : "/dev/mapper/centos-root" , "fstype" : "xfs" , "inode_available" : 31285667, "inode_total" : 31350784, "inode_used" : 65117, "mount" : "/" , "options" : "rw,relatime,attr2,inode64,noquota" , "size_available" : 60258545664, "size_total" : 64175054848, "uuid" : "03898aec-07c2-4cd9-a21f-a8da8c857d12" }, { "block_available" : 0, "block_size" : 4096, "block_total" : 0, "block_used" : 0, "device" : "/etc/auto.nfs" , "fstype" : "autofs" , "inode_available" : 0, "inode_total" : 0, "inode_used" : 0, "mount" : "/nas" , "options" : "rw,relatime,fd=17,pgrp=1224,timeout=60,minproto=5,maxproto=5,indirect,pipe_ino=29960" , "size_available" : 0, "size_total" : 0, "uuid" : "N/A" }, { "block_available" : 5232051, "block_size" : 4096, "block_total" : 5240320, "block_used" : 8269, "device" : "/dev/mapper/centos-opt" , "fstype" : "xfs" , "inode_available" : 10485747, "inode_total" : 10485760, "inode_used" : 13, "mount" : "/opt" , "options" : "rw,relatime,attr2,inode64,noquota" , "size_available" : 21430480896, "size_total" : 21464350720, "uuid" : "8b644eea-a8c6-493c-a1de-6872350348fa" }, { "block_available" : 0, "block_size" : 4096, "block_total" : 0, "block_used" : 0, "device" : "/etc/auto.misc" , "fstype" : "autofs" , "inode_available" : 0, "inode_total" : 0, "inode_used" : 0, "mount" : "/misc" , "options" : "rw,relatime,fd=5,pgrp=1224,timeout=300,minproto=5,maxproto=5,indirect,pipe_ino=29103" , "size_available" : 0, "size_total" : 0, "uuid" : "N/A" } ], "ansible_nodename" : "70" , "ansible_os_family" : "RedHat" , "ansible_pkg_mgr" : "yum" , "ansible_proc_cmdline" : { "BOOT_IMAGE" : "/vmlinuz-3.10.0-1127.18.2.el7.x86_64" , "LANG" : "zh_CN.UTF-8" , "biosdevname" : "0" , "crashkernel" : "auto" , "net.ifnames" : "0" , "quiet" : true , "rd.lvm.lv" : "centos/root" , "rhgb" : true , "ro" : true , "root" : "/dev/mapper/centos-root" }, "ansible_processor" : [ "0" , "GenuineIntel" , "Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz" , "1" , "GenuineIntel" , "Intel(R) Xeon(R) CPU E5-2640 v4 @ 2.40GHz" ], "ansible_processor_cores" : 1, "ansible_processor_count" : 2, "ansible_processor_threads_per_core" : 1, "ansible_processor_vcpus" : 2, "ansible_product_name" : "VMware Virtual Platform" , "ansible_product_serial" : "VMware-42 37 7d 76 da 3a 3c 35-b0 98 cd c1 b1 c7 45 6c" , "ansible_product_uuid" : "767D3742-3ADA-353C-B098-CDC1B1C7456C" , "ansible_product_version" : "None" , "ansible_python" : { "executable" : "/usr/bin/python" , "has_sslcontext" : true , "type" : "CPython" , "version" : { "major" : 2, "micro" : 5, "minor" : 7, "releaselevel" : "final" , "serial" : 0 }, "version_info" : [ 2, 7, 5, "final" , 0 ] }, "ansible_python_version" : "2.7.5" , "ansible_real_group_id" : 0, "ansible_real_user_id" : 0, "ansible_selinux" : { "status" : "disabled" }, "ansible_selinux_python_present" : true , "ansible_service_mgr" : "systemd" , "ansible_ssh_host_key_ecdsa_public" : "AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMVR+t8GxxbwQGBy4DUA1/nEzdslI1nMSezDzLn56SdoAZ6oxJceFTiXuwGeTcFneXxYWhCu3KoSYaJ2dCr5L90=" , "ansible_ssh_host_key_ed25519_public" : "AAAAC3NzaC1lZDI1NTE5AAAAIKQkRbP/HAZvTZnO0nokggBV9fD5KdWC7B72+d5ZNBLz" , "ansible_ssh_host_key_rsa_public" : "AAAAB3NzaC1yc2EAAAADAQABAAABAQDPZbl6hL0f/4n4es3Pvn9mdJ4VObvmaAojLa8Iu0exs3/HZE2aCERIosxJJUJbzJCb6d5/6ynjG0E4UpEsd7HRVX4ewdIs/1NdYeUp0DrGXrnjN2+1ZS2B4HNWLOs8SPXOdbHS1dlC8iNIvr9rX0taTnn2AibHpd3wD3KzoId3Hgd7Rc5/PpUgvslG5+zgRBuIjfCifmcj6dSczfJlBlKIXaQxvhZ6u1TU6nS0dWkFY+cFaTzNAiGLTix1LH30YMqHaavT4J05JkzRT6BU70Bxaae91oVxjvhSgB4+/X2UGMT/1ymhHiC9nHUwt4fKpuYUWu3LQsKypMBg6N1NEhQ5" , "ansible_swapfree_mb" : 0, "ansible_swaptotal_mb" : 0, "ansible_system" : "Linux" , "ansible_system_capabilities" : [ "cap_chown" , "cap_dac_override" , "cap_dac_read_search" , "cap_fowner" , "cap_fsetid" , "cap_kill" , "cap_setgid" , "cap_setuid" , "cap_setpcap" , "cap_linux_immutable" , "cap_net_bind_service" , "cap_net_broadcast" , "cap_net_admin" , "cap_net_raw" , "cap_ipc_lock" , "cap_ipc_owner" , "cap_sys_module" , "cap_sys_rawio" , "cap_sys_chroot" , "cap_sys_ptrace" , "cap_sys_pacct" , "cap_sys_admin" , "cap_sys_boot" , "cap_sys_nice" , "cap_sys_resource" , "cap_sys_time" , "cap_sys_tty_config" , "cap_mknod" , "cap_lease" , "cap_audit_write" , "cap_audit_control" , "cap_setfcap" , "cap_mac_override" , "cap_mac_admin" , "cap_syslog" , "35" , "36+ep" ], "ansible_system_capabilities_enforced" : "True" , "ansible_system_vendor" : "VMware, Inc." , "ansible_uptime_seconds" : 949193, "ansible_user_dir" : "/root" , "ansible_user_gecos" : "root" , "ansible_user_gid" : 0, "ansible_user_id" : "root" , "ansible_user_shell" : "/bin/bash" , "ansible_user_uid" : 0, "ansible_userspace_architecture" : "x86_64" , "ansible_userspace_bits" : "64" , "ansible_virtualization_role" : "guest" , "ansible_virtualization_type" : "VMware" , "discovered_interpreter_python" : "/usr/bin/python" , "gather_subset" : [ "all" ], "module_setup" : true }, "changed" : false } |
返回信息如上,是一个json格式的字符串,为了方便你阅读,ansible已经将格式化后的json信息返回到了控制台中,返回的信息很全面,比如:
"ansible_all_ipv4_addresses"表示远程主机中的所有ipv4地址,从其对应的值可以看出,test70主机上一共有4个ipv4地址。
"ansible_distribution"表示远程主机的系统发行版,从其对应的值可以看出test70主机的系统发行版为centos
"ansible_distribution_version"表示远程主机的系统版本号,从其对应的值与 "ansible_distribution" 的值可以看出test70主机的系统版本为centos7.4
"ansible_ens35"表示远程主机ens35网卡的相关信息,细心如你一定也发现了,我还有两个名为"ens33"和"ens34"的网卡,只不过为了方便示例,这两个网卡的信息被我省略了。
"ansible_memory_mb"表示远程主机的内存配置信息。
返回的信息的确很多,很全面,但是,并不是每一次我们都需要看这么多信息,如果你只是想查看某一类信息,你可以通过关键字对信息进行过滤,比如,我只是想要查看远程主机的内存配置信息,那么我可以使用如下命令
上述命令表示通过"ansible_memory_mb"关键字对返回信息进行过滤,如你所见,通过setup模块的filter参数可以指定需要过滤的关键字,这样ansible就只会将"ansible_memory_mb"的相关信息返回,返回如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [root@node1 ansible]# ansible test70 -m setup -a 'filter=ansible_memory_mb' test70 | SUCCESS => { "ansible_facts" : { "ansible_memory_mb" : { "nocache" : { "free" : 5413, "used" : 392 }, "real" : { "free" : 3914, "total" : 5805, "used" : 1891 }, "swap" : { "cached" : 0, "free" : 0, "total" : 0, "used" : 0 } }, "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : false } |
这样就精简很多了,因为精准的返回了你需要的信息,我知道,有的朋友可能跟我一样,记性不好,所以通常记不住准确的关键字,所以我们可以使用通配符,进行相对模糊的过滤,示例如下
1 | ansible test70 -m setup -a "filter=*mb*" |
上述命令表示返回所有包含mb的关键字对应的信息
其实,除了这些信息以外,我们还能够在远程主机中写入一些自定义的信息,这些自定义信息也可以被setup模块收集到。
那么,我们应该在哪里定义这些信息呢?该怎样定义这些信息呢?ansible默认会去目标主机的/etc/ansible/facts.d目录下查找主机中的自定义信息,并且规定,自定义信息需要写在以".fact"为后缀的文件中,同时,这些以".fact"为后缀的文件中的内容需要是INI格式或者是json格式的。
那么,我们来创建一个测试文件,测试文件路径为test70主机的/etc/ansible/facts.d/testinfo.fact,在文件中写入如下INI格式的信息。
1 2 3 4 | [root@70 facts.d]# cat /etc/ansible/facts.d/testinfo.fact [testmsg] msg1=This is the first custom test message msg2=This is the second custom test message |
如上所示,上述内容是一段INI风格的内容,我在"[testmsg]"配置段中配置了两条自定义信息,msg1与msg2。
当然,我们也可以使用json格式进行配置,比如在/etc/ansible/facts.d/testinfo.fact文件中写入如下配置,如下配置与上述配置的效果是相同的,只是书写格式不同。
1 2 3 4 5 6 | { "testmsg" :{ "msg1" : "This is the first custom test message" , "msg2" : "This is the second custom test message" } } |
通过上述方式,我们可以在目标主机的本地自定义信息,这些在远程主机本地自定义的信息被称为"local facts",当我们运行setup模块时,远程主机的"local facts"信息也会被收集,我们可以通过"ansible_local"关键字过滤远程主机的"local facts"信息,示例命令如下
1 | ansible test70 -m setup -a 'filter=ansible_local' |
上述命令返回的信息如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | test70 | SUCCESS => { "ansible_facts" : { "ansible_local" : { "testinfo" : { "testmsg" : { "msg1" : "This is the first custom test message" , "msg2" : "This is the second custom test message" } } }, "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : false } |
之前说过,当setup收集远程主机的"local facts"时,默认会查找远程主机的/etc/ansible/facts.d目录,如果你把"local facts"信息文件放在了其他自定义路径,在使用setup模块时,需要使用"fact_path"参数指定对应的路径,假设,我把".fact"文件放在了目标主机的"/testdir"目录下,示例命令如下
1 | ansible test70 -m setup -a 'fact_path=/testdir' |
其实,setup模块返回的这些信息都存在了对应的变量中,我们可以通过引用变量从而使用对应的信息,但是别急,我们先来了解一下另外一个模块,这个模块叫"debug模块"。
见名知义,debug模块的作用就是帮助我们进行调试的,debug模块可以帮助我们把信息输出到ansible控制台上,以便我们能够定位问题。
那么我们先来看一个debug模块的playbook小示例,如下
1 2 3 4 5 6 7 8 9 10 11 12 | [root@node1 ansible]# cat test4.yml --- - hosts: test70 remote_user: root tasks: - name: touch testfile file: path: /testdir/testfile state: touch - name: debug demo debug: msg: this is debug info,The test file has been touched |
上例中,我们先在test70主机上touch了对应的文件,然后,利用debug模块在控制台中输出了我们想要显示的信息,如你所见,debug模块的msg参数可以指定我们想要输出的信息,上述playbook表示touch完对应的文件以后,在ansible控制台中输出我们指定的信息,那么我们运行一下这个测试剧本,看一下效果,如下
如图所示,自定义信息已经输出在ansible控制台中。
debug模块除了能够使用msg参数输出自定义的信息,还能够直接输出变量中的信息,通过debug模块直接输出变量信息需要使用var参数,示例如下
1 2 3 4 5 6 7 8 9 10 | [root@node1 ansible]# cat test5.yml --- - hosts: test70 remote_user: root vars: testvar: value of test variable tasks: - name: debug demo debug: var : testvar |
上例虽然连接到了test70远程主机,但是并没有对test70做任何操作,只是在playbook中定义了一个变量,并且通过debug的var参数输出了这个变量的内容,只是为了单纯的演示debug模块的var参数的使用方法,上述playbook的执行效果如下
变量的名称以及变量的值都输出到了屏幕上,这个功能可以帮助我们调试playbook中变量,让我们了解变量的值是否符合我们的要求。
当然,使用debug的msg参数时也可以引用变量的值,这样我们自定义的信息就更加灵活了,示例如下。
1 2 3 4 5 6 7 8 9 10 | [root@node1 ansible]# cat test6.yml --- - hosts: test70 remote_user: root vars: testvar: testv tasks: - name: debug demo debug: msg: "value of testvar is :{{testvar}}" |
上例中的msg自定义信息中引用了testvar变量的值
注:上例中msg的值需要使用引号引起,因为{{testvar}}变量前包含"冒号",如果不使用引号会报语法错误。
上例输出效果如下
setup模块与debug模块了解完了,现在绕回一开始的话题,playbook在运行时默认都会运行"[Gathering Facts]"任务,"[Gathering Facts]"任务会收集远程主机的相关信息,这些信息会保存在对应的变量中,我们在playbook中可以使用这些变量,从而利用这些信息,那么我们怎样在playbook获取到这些变量的值呢?在setup模块的示例中,我们可以通过"ansible_memory_mb"关键字获取远程主机的内存信息,其实,"ansible_memory_mb"就是一个变量名,换句话说就是,我们可以在playbook中直接引用名为"ansible_memory_mb"的变量,从而获取到远程主机的内存信息,示例如下
1 2 3 4 5 6 7 8 | [root@node1 ansible]# cat test7.yml --- - hosts: test70 remote_user: root tasks: - name: debug demo debug: msg: "Remote host memory information is :{{ansible_memory_mb}}" |
上例执行效果如下
如图所示,我们自定义的信息中包含了远程主机的内存信息,同时被输出了,只是格式上没有手动执行setup模块返回的信息格式易读,手动执行setup模块获取到的内存信息返回如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | [root@node1 ansible]# !1021 ansible test70 -m setup -a 'filter=ansible_memory_mb' test70 | SUCCESS => { "ansible_facts" : { "ansible_memory_mb" : { "nocache" : { "free" : 5410, "used" : 395 }, "real" : { "free" : 3911, "total" : 5805, "used" : 1894 }, "swap" : { "cached" : 0, "free" : 0, "total" : 0, "used" : 0 } }, "discovered_interpreter_python" : "/usr/bin/python" }, "changed" : false } |
如上述返回信息所示,"ansible_memory_mb"中其实包含了 "nocache"、"real"、 "swap"三个部分的信息,如果我们只想获得"real"部分的信息,在playbook中引用变量时可以使用如下两种语法。
1 2 3 4 5 6 7 | 语法一示例: debug: msg: "Remote host memory information : {{ansible_memory_mb.real}}" 语法二示例: debug: msg: "Remote host memory information : {{ansible_memory_mb['real']}}" 上述两种语法前文中已经进行过示例,此处不再赘述。 |
其实,这些远程主机的变量信息不仅仅能够用于输出,我们通常会获取到这些信息以后,对这些信息的值进行判断,判断是否符合我们的要求,然后再执行下一步动作,比如,先获取到远程主机的系统发行版信息,然后判断发行版是centos6还是centos7,如果是centos6,我们就将准备好的A文件拷贝到远程主机中,如果是centos7,我们就将准备好的B文件拷贝到远程主机中,不过由于我们还没有总结条件判断的相关使用方法,所以此处就不进行示例了。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析